6

我有一个 .NET 应用程序的转储,它创建并加载了太多动态程序集。我想检查其中一个程序集里​​面有什么。

为此,我想将这样的程序集转储到文件中并在 Reflector 中打开它。

问题 - 我不知道该怎么做。

所以,我的问题是——给定一个完整的内存转储,我如何将任意程序集转储到文件中,以使新文件是有效的 .NET 模块或程序集本身?

一个更简单的变体 - 我如何从实时调试会话中做到这一点?

我正在使用带有 SOS 和 SOSEX 的 WinDBG。

编辑 1

所以,3年后我再次需要它。以下是来自的相关输出!DumpDomain

Assembly:           007f89a0 (Dynamic) []
ClassLoader:        00877998
SecurityDescriptor: 00879410
  Module Name
054d0010    Dynamic Module

从这些信息开始,我怎样才能找到这个程序集的开始和结束?然后我可以使用.writemem命令。

4

3 回答 3

4

测试代码 - 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

不如反射器好,但你可以看到类型和方法。

于 2013-11-16T02:48:19.500 回答
1

您可以使用.imgscan. 我在内存中有动态程序集时这样做了,但.imgscan没有找到它。它没有典型的MZ标头,因此反射创建的程序集似乎不是可以保存到磁盘的 DLL 文件。否则,您可以使用.writemem将其保存到磁盘。

于 2013-12-26T21:29:30.843 回答
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 列表中,那么这应该不是问题。如果没有,那么您将需要找到它被加载到内存中的位置并将其用作起始地址。

于 2013-11-13T03:10:29.343 回答