概述:360 DNRSP(.NET RASP 引擎)一次 w3wp 崩溃的完整取证,仅凭 minidump 的 UTF-16 字符串定位到 .NET 反射版本不匹配(Assembly.get_Modules() 在 .NET Framework 4.0 缺失)导致 MissingMethodException 的根因。

[toc]

0x00 TL;DR

  • 崩溃进程:w3wp.exe(IIS worker),承载 DesktopMsgServer 应用。
  • 崩溃引擎:360 DNRSP(DnrspEngine.dll / DnrspCore.dll / DnrspSDK.dll),.NET RASP 运行时防护引擎。
  • 异常类型:MissingMethodException(伴生一条 AccessException)。
  • 异常消息:
Method not found: 'System.Collections.Generic.IEnumerable`1<System.Reflection.Module>
System.Reflection.Assembly.get_Modules()'.
  • 根因:DNRSP 引擎在 HookLoader 初始化/遍历程序集模块时,通过反射硬编码调用 Assembly.get_Modules()。该属性是 .NET Framework 4.5+ 才引入的新 API(返回 IEnumerable<Module>),而客户环境是未升级的 .NET Framework 4.0.30319.1(RTMRel),反射找不到该属性 → 抛 MissingMethodException → 引擎初始化失败 → 宿主进程崩溃。

0x01 取证环境与 dump 概况

  • dump 文件:360dnrsp_crash.dmp,约 2.88 MB(minidump,非全量 dump)。
  • 生成器:D:\Program Files (x86)\360\360Safe\DumpUper.exe(360 自家 dump 工具)。
  • dump 版本:0x61b1a793,12 个 stream。

取证过程的坑(绕过损坏的结构)

本 dump 的 ExceptionStream 解析出 NumberOfParameters = 533313 这类不合理值,且 RVA 0x5dbff + size 149172 越界(超出文件大小),说明 ExceptionStream 损坏/截断ModuleList 按 48 字节 stride 解析出乱码,暗示 dump-writer 产出的结构是 32/64 位混用。

结论:放弃 struct 逐流解析,改用字符串级取证——strings -a -e l(UTF-16LE)全量扫描,直接 grep 托管异常消息文本,一击命中根因。

bash
strings -a -e l 360dnrsp_crash.dmp | grep -iE "method not found|get_Modules|getModules"

命中(原文,出现两次):

Method not found
Method not found: 'System.Collections.Generic.IEnumerable`1<System.Reflection.Module> System.Reflection.Assembly.get_Modules()'.
ot found: 'System.Collections.Generic.IEnumerable`1<System.Reflection.Module> System.Reflection.Assembly.get_Modules()'.

0x02 根因机制

Assembly.get_Modules vs Assembly.GetModules

API引入版本返回类型说明
Assembly.GetModules().NET Framework 1.0Module[]老 API,一路都有
Assembly.get_Modules().NET Framework 4.5IEnumerable<Module>新属性(C# 中写作 assembly.Modules),LINQ 友好
  • 编译到 C# 源码里,assembly.Modules 这一语法糖在 IL 层就是 get_Modules() 属性 getter。
  • 若引擎源码里写了 assembly.Modules,且编译目标框架为 4.5+,那么在 4.0 环境的 mscorlib 上就没有这个 getter → 反射调用抛 MissingMethodException

DNRSP 引擎侧的触发点

dump 字符串体现引擎 hook 初始化路径:

DnrspEngine.HookLoader
DnrspEngine.HookLoaderDomain
EngineMarshalLoader, dnrspengine

推断:HookLoader 在装载引擎、遍历目标程序集模块(做 IL 改写/反序列化 hook 插桩)时,调用了 assembly.get_Modules(),在 4.0 环境直接炸掉。

反序列化 hook 目标(引擎角色佐证)

AjaxPro.JavaScriptDeserializer@DeserializeCustomObject
System.Web.UI.ObjectStateFormatter@DeserializeValue

符合 DNRSP 作为反序列化 RASP 的定位——它在这些反序列化入口下 hook 点做防护,而遍历模块正是插桩的前置动作。

0x03 框架版本铁证

dump 字符串中存在:

4.0.30319.1 (RTMRel.030319-0100)
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll

4.0.30319.1 + RTMRel.030319-0100 说明客户环境是纯 .NET Framework 4.0 初始发行版,未打 4.5+ 升级(升级后 mscorlib 会带 get_Modules getter)。

0x04 与既有 DNRSP 崩溃工作链的关系(重要区分)

场景根因异常类型
广德佳联 K3Cloud(历史案例)SuppressUnmanagedCodeSecurity 缺失 → DemandPermission CAS 栈遍历 → CLR ExecutionEngineExceptionEEE(进程级致命)
本次 DesktopMsgServer反射硬编码 get_Modules() → 4.0 无该 APIMissingMethodException

两者不是同一类缺陷

  • 前者是 .NET CAS 运行时安全机制(CAS/APTCA/SuppressUnmanagedCodeSecurity)在异常状态下的崩溃,属于”运行时安全基础设施”维度。
  • 本次是引擎假设过高框架版本的纯版本兼容问题,属于”改前查现状”教训的延伸——查的是框架版本,而非编码惯例。

0x05 修复建议

  • 环境侧:客户服务器升级 .NET Framework 到 4.8(get_Modules 存在,且顺带获得安全补丁)。
  • 引擎侧(更稳)HookLoader 遍历模块时做降级兼容——先反射探测 get_Modules 是否存在,不存在则回退调用老 API Assembly.GetModules()(4.0 一直可用),或整体 try/catch 包裹,避免单点反射失败拖垮宿主进程(符合”引擎异常永不升级宿主崩溃”的容错红线)。

0x06 小结

一次 w3wp 崩溃的精确定位,靠的不是 WinDbg(环境里没有 cdb/windbg/dotnet-dump),而是 minidump 里的托管异常消息字符串。当 dump 的异常流损坏、调试器缺失时,strings -a -e l 扫 UTF-16 字符串是 .NET dump 取证最实用的兜底手段——.NET 的异常消息、类型名、框架版本号都以 UTF-16 明文躺在 dump 里。

0x07 WinDbg 复验步骤

拿到 WinDbg 后,可按以下顺序独立复证上述结论。

7.1 定位崩溃线程与异常记录

  • !analyze -v:查看 EXCEPTION_CODE(应为 0xe0434352,即 CLR 未处理异常)与 FAULTING_THREAD 号。
  • ~* e .exr -1:遍历所有线程打印异常记录,寻找带 0xe0434352 的那条,即崩溃线程。

本 dump 的 ExceptionStream 损坏,导致 !pe 直接报 Not a valid exception object,但只要异常消息字符串仍在内存中,~* e .exr -1 即可在异常记录里直接看到 Method not found ... Assembly.get_Modules() 的原文,是最快、最不依赖 SOS 的复验手段。

7.2 切换线程 + 加载 SOS

~<崩溃线程号> s
.load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll

注意:不要 .load clr.dll——clr.dll 是运行库 DLL,不是 WinDbg 扩展,.load 只用于扩展。

7.3 读托管堆栈(定位 HookLoader)

  • !threads:列出托管线程,找 Exception 列非空的线程。
  • !clrstack / !dumpstack:看托管/混合调用栈,期望出现 DnrspEngine.HookLoader 及相关反射调用帧。

7.4 内存字符串独立搜证

s -u 0 L?ffffffff "Method not found"
s -u 0 L?ffffffff "get_Modules"

命中后用 du <地址> 打印完整 UTF-16 消息,与 dump 字符串取证相互印证。

7.5 验证框架版本

lmvm mscorlib

输出应落在 Framework64\v4.0.30319、版本 4.0.30319.1,佐证环境未升级 4.5+(无 get_Modules)。

结论验证清单

分析结论WinDbg 验证手段期望输出
.NET 未处理异常!analyze -v0xe0434352
异常消息含 get_Modules()~* e .exr -1s -uMethod not found: ...get_Modules()
异常类型!pe(需有效异常对象)System.MissingMethodException
触发点 HookLoader!clrstackDnrspEngine.HookLoader
环境 .NET 4.0lmvm mscorlib4.0.30319.1