我有一个.NET应用程序的转储,它创建并加载了太多的动态程序集。我想检查一下这些组件中的内容。
为此,我想将这样的程序集转储到文件中并在Reflector中打开它。
问题 - 我不知道该怎么做。
所以,我的问题是这个 - 给定一个完整的内存转储,如何将一个任意的程序集转储到一个文件中,使新文件是一个有效的.NET模块或程序集本身?
更简单的变化 - 如何从实时调试会话中完成?
我正在使用带有SOS和SOSEX的WinDBG。
编辑1
所以,3年后我再次需要它。以下是!DumpDomain
的相关输出:
Assembly: 007f89a0 (Dynamic) []
ClassLoader: 00877998
SecurityDescriptor: 00879410
Module Name
054d0010 Dynamic Module
从这些信息开始,我如何找到此程序集的开头和结尾?然后我可以使用.writemem
命令。
答案 0 :(得分:3)
测试代码 - http://www.dotnetspider.com/resources/22226-Creating-Dynamic-Assembly-A-Step-Ahead-Series.aspx
0:000> !DumpDomain
Assembly: 00680f48 (Dynamic) []
ClassLoader: 00681010
SecurityDescriptor: 00680eb0
Module Name
0058386c Dynamic Module
0:000> !DumpModule -mt 0058386c
Name: Unknown Module
Attributes: Reflection SupportsUpdateableMethods
Assembly: 00680f48
LoaderHeap: 00000000
TypeDefToMethodTableMap: 00581b54
TypeRefToMethodTableMap: 00581b68
MethodDefToDescMap: 00581b7c
FieldDefToDescMap: 00581ba4
MemberRefToDescMap: 00000000
FileReferencesMap: 00581bf4
AssemblyReferencesMap: 00581c08
Types defined in this module
MT TypeDef Name
------------------------------------------------------------------------------
00583c98 0x02000002 <Unloaded Type>
Types referenced in this module
MT TypeRef Name
------------------------------------------------------------------------------
726826a0 0x02000001 System.Object
72647e4c 0x02000002 System.Console
0:000> !DumpMT -md 00583c98
EEClass: 0060121c
Module: 0058386c
Name: <Unloaded Type>
mdToken: 02000002
File: Unknown Module
BaseSize: 0xc
ComponentSize: 0x0
Slots in VTable: 6
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDe JIT Name
7258a630 7227801c PreJIT System.Object.ToString()
7257f750 72278024 PreJIT System.Object.Equals(System.Object)
7257f380 72278044 PreJIT System.Object.GetHashCode()
7257f040 72278058 PreJIT System.Object.Finalize()
005f03d0 00583c90 JIT dynamicAssemblyClass..ctor()
005f03e8 00583c84 JIT dynamicAssemblyClass.HelloWorld()
0:000> !DumpIL 00583c84
FindIL failed
0:000> !U 005f03e8
Normal JIT generated code
dynamicAssemblyClass.HelloWorld()
Begin 005f03e8, size 1a
>>> 005f03e8 55 push ebp
005f03e9 8bec mov ebp,esp
005f03eb e8b856f871 call mscorlib_ni!System.Console.get_Out() (72575aa8)
005f03f0 8bc8 mov ecx,eax
005f03f2 8b15a0210703 mov edx,dword ptr ds:[30721A0h] ("Hello! This is a dynamic assembly.")
005f03f8 8b01 mov eax,dword ptr [ecx]
005f03fa 8b403c mov eax,dword ptr [eax+3Ch]
005f03fd ff5010 call dword ptr [eax+10h]
005f0400 5d pop ebp
005f0401 c3 ret
不如反射器好,但你可以看到类型和方法。
答案 1 :(得分:1)
您可以使用.imgscan
扫描整个虚拟内存中的DLL。我在内存中运行动态程序集时执行了此操作,但.imgscan
未找到它。它没有典型的MZ
标头,因此反射创建的程序集似乎不是可以保存到磁盘的DLL文件。否则,您可以使用.writemem
将其保存到磁盘。
答案 2 :(得分:0)
您需要使用SOS中提供的!SaveModule命令。它有两个参数:1)起始地址和2)导出路径。您可以通过使用lmv检查模块详细信息来找到起始地址。
例如,如果要导出clr.dll,请先键入lmv m clr以验证起始地址。可以说它是000007fe`f9b40000。让我们将它保存到c:\ clr.dll。该命令现在变为如下:
!sos.SaveModule 000007fe`f9b40000 c:\clr.dll
现在检查模块的导出路径。 这将从实时调试会话以及完整(/ ma)转储开始。
我不确定动态装配。如果它们出现在lm列表中,那么它应该不是问题。如果没有,那么您将需要找到它加载到内存的位置并将其用作起始地址。