惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Webroot Blog
Webroot Blog
U
Unit 42
A
About on SuperTechFans
宝玉的分享
宝玉的分享
月光博客
月光博客
C
CERT Recently Published Vulnerability Notes
P
Privacy International News Feed
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
P
Privacy & Cybersecurity Law Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
Securelist
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
Apple Machine Learning Research
Apple Machine Learning Research
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
B
Blog
I
Intezer
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
V
V2EX
L
LangChain Blog
AI
AI
G
GRAHAM CLULEY
T
Tor Project blog
人人都是产品经理
人人都是产品经理
D
Docker
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
I
InfoQ
Y
Y Combinator Blog
C
Comments on: Blog
GbyAI
GbyAI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
aimingoo的专栏
aimingoo的专栏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
H
Help Net Security
Vercel News
Vercel News
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
爱范儿
爱范儿

博客园 - Demon521

博文阅读密码验证 - 博客园 博文阅读密码验证 - 博客园 流浪歌手弹唱震撼心灵(很震撼心灵!) 爱,永远禁不起等待 好男人找不到女朋友的根源 男女交往必知15个真理 上海地铁车费没有必要大于6元 CLR探索系列:Windbg+SOS动态调试分析托管代码 (转) Windbg寻找Managed Founction参数值 (转) WinDbg+SOS:Web服务器High CPU Hang(100%)实例分析 (转) 使用WinDbg+SOS及WinDbg Script寻找内存中DataTable第M行N列的值 (转) Windbg在Managed App中设置函数断点的几种方法 (转) 线程之间的通讯---SynchronizationContext (转) 世界顶级精英们的人生哲学! 各类搜索网站 快速找到并输入连接数据源的字符串 UML中依赖/泛化/关联/实现/聚合/组合的C#实现 [转] 最最常用的DOS Command 最常用的Windows快捷键
CLR探索系列:Windbg+SOS剖析揭示域世界 (转)
Demon521 · 2009-01-13 · via 博客园 - Demon521

在CLR的世界中,有一系列的令人Amazing的技术和架构。其中,CLR对应用程序在内存中内存分配,执行模型,程序之间的交互等一系列的技术,值得每一个致力于DotNet平台的技术人员深究。
编程人员在开发的过程中,如果把程序集的加载(Assemblies Load)反射(Reflection)寄宿(Hosting)应用程序域(AppDomain),这四种技术结合起来使用的话,不仅能更好的使用CLR这个平台提供的强大的功能,而且能够构建更安全,更健壮的应用程序代码。

这篇博文里,就是使用托管代码的动态调试工具,来研究一下CLR内部

AppDomain的世界。

首先,从一个C#程序开始:
    class Program
    {
        static void Main(string[] args)
        {
            Program b = new Program();
            b.test();
            System.Console.ReadLine();
        }

        public void test()
        {
            int i = 67;
            System.Console.WriteLine((char)i);
            System.Console.WriteLine((char)67);
            i = 1;
        }
    }

运行了这个应用程序以后,我们打开windbg,attach到这个托管进程。

.load SOS
加载SOS扩展调试模块,可以使用.chain指令查看加载是否正确。
0:003> lm
start    end        module name
00400000 00408000   TestConcoleApp   (deferred)            
76990000 76acd000   ole32      (deferred)            
77be0000 77c38000   msvcrt     (deferred)             
省略若干
77fc0000 77fd1000   Secur32    (deferred)            
78130000 781cb000   MSVCR80    (deferred)            
79000000 79045000   mscoree    (deferred)            
79060000 790b3000   mscorjit   (deferred)            
790c0000 79b90000   mscorlib_ni   (deferred)            
79e70000 7a3d6000   mscorwks   (deferred)            
查看下意境加载了的模块,然后使用ld命令把我们的调试符号文件载入。VS在编译生成一个Console App的时候,在debug模式的时候会在debug的bin目录下生成一个和应用程序同名的pdb文件。我们要做的,就是载入这个文件:0:003> ld TestConcoleApp
*** WARNING: Unable to verify checksum for G:\Projects\TestConcoleApp\TestConcoleApp\bin\Debug\TestConcoleApp.exe
Symbols loaded for TestConcoleApp
有一个警告,咋这里先不管,再使用lm查看已经加载了的模块的时候,可以看到这个module的调试符号文件已经被加载上了。

此时,我们可以查看下Excute Engine (CLR)的堆里面都有些什么东西,我们可以使用!EEHeap命令,EE的意思,就是CLI的执行引擎,也就是我们常说的CLR。这个命令可以查看到一个托管进程里面的garbage-collected 和 Loader heaps相关信息。

0:003> !eeheap
PDB symbol for mscorwks.dll not loaded
Loader Heap:
--------------------------------------
System Domain: 7a38f918
LowFrequencyHeap: Size: 0x0(0)bytes.
HighFrequencyHeap: 00a62000(8000:1000) Size: 0x1000(4096)bytes.
StubHeap: 00a6a000(2000:1000) Size: 0x1000(4096)bytes.
Virtual Call Stub Heap:
  IndcellHeap: Size: 0x0(0)bytes.
  LookupHeap: Size: 0x0(0)bytes.
  ResolveHeap: Size: 0x0(0)bytes.
  DispatchHeap: Size: 0x0(0)bytes.
  CacheEntryHeap: Size: 0x0(0)bytes.
Total size: 0x2000(8192)bytes
/**********************************************
Loader Heap 中的系统域。这个域和下面的Shared Domian一起,是对托管的宿主程序,以及托管代码不可见的。这个域加载了两个CLR执行中十分重要的Module,MSCorEE.dll和MScorwks.dll。MSCorEE.dll这个文件就是大家熟悉的shim,垫片。在CLR加载中起到的重要作用。这里就不分析了,大家可以参考别的文献的介绍。
对于每个应用程序域,都会有自己的安全描述符,安全上下文以及默认的上下文。这三个部分可以支持一个应用程序域来自定义一个单独实施的安全策略,譬如,可以用来确保宿主程序在加载托管代码的时候不会对这些重要的数据结构造成破坏。
**********************************************/

--------------------------------------
Shared Domain: 7a38fef0
LowFrequencyHeap: 00a90000(2000:1000) Size: 0x1000(4096)bytes.
HighFrequencyHeap: Size: 0x0(0)bytes.
StubHeap: 00a9a000(2000:1000) Size: 0x1000(4096)bytes.
Virtual Call Stub Heap:
  IndcellHeap: Size: 0x0(0)bytes.
  LookupHeap: Size: 0x0(0)bytes.
  ResolveHeap: 00aab000(5000:1000) Size: 0x1000(4096)bytes.
  DispatchHeap: 00aa7000(4000:1000) Size: 0x1000(4096)bytes.
  CacheEntryHeap: Size: 0x0(0)bytes.
Total size: 0x4000(16384)bytes
/**********************************************
在共享域中,加载所有的应用程序域中都要使用到的assemblies,譬如MScorlib.dll。装载了System.Object,System.ValueType这样的基础类。
**********************************************/

--------------------------------------
Domain 1: 154250
LowFrequencyHeap: 00a70000(2000:2000) Size: 0x2000(8192)bytes.
HighFrequencyHeap: 00a72000(8000:2000) Size: 0x2000(8192)bytes.
StubHeap: Size: 0x0(0)bytes.
Virtual Call Stub Heap:
  IndcellHeap: Size: 0x0(0)bytes.
  LookupHeap: Size: 0x0(0)bytes.
  ResolveHeap: Size: 0x0(0)bytes.
  DispatchHeap: Size: 0x0(0)bytes.
  CacheEntryHeap: Size: 0x0(0)bytes.
Total size: 0x4000(16384)bytes
/**********************************************
对于特定的寄宿程序,可以根据需要创建多个应用的默认域。例如IE,Asp.Net,或者是SqlServer,可以创建一个或者是多个默认的域。域名默认情况下的name就是module的名称。
在默认域中,应用程序执行的时候需要装载经来的assemblies可以被加载到这里。
在每个应用程序域中,代码创建的对象不能直接访问另外的应用程序域中的代码。如果要访问这些代码,可以采用静态的委托,或者是appDomain的自己的方法来实现。
**********************************************/

--------------------------------------
Jit code heap:
LoaderCodeHeap: 00db0000(10000:1000) Size: 0x1000(4096)bytes.
Total size: 0x1000(4096)bytes
对于托管的应用程序,有两种把IL代码编译成本地代码的方式。一种是在第一次运行的时候,调用JIT模块来实时编译,编译好了的本地代码就放到这里。在PE文件中的相应的代码处,就用一个指针指引CLR到这里来找相关的编译好了的本地代码。第二中是安装的时候就编译成为本地代码。
同时可以看到,Jit Heap占用很少的内存空间。
--------------------------------------
Module Thunk heaps:
Module 790c2000: Size: 0x0(0)bytes.
Module 00a72c24: Size: 0x0(0)bytes.
Total size: 0x0(0)bytes
--------------------------------------
Module Lookup Table heaps:
Module 790c2000: Size: 0x0(0)bytes.
Module 00a72c24: Size: 0x0(0)bytes.
Total size: 0x0(0)bytes

--------------------------------------
Total LoaderHeap size: 0xb000(45056)bytes

总共的loader Heap的大小大概在45kb左右。
=======================================
Number of GC Heaps: 1
generation 0 starts at 0x013b1018
generation 1 starts at 0x013b100c
generation 2 starts at 0x013b1000
ephemeral segment allocation context: none
下面的这两个segment对于应用程序域的其他代码来说是read only的,所以,这两部分的空间比较小。这块经常保存的是小的segement片段。除非你是很长很长的字符串。而大的object,则保持在LOH中。GC Heap,可以有多个。每个GC Heap中,都可以有一个LOH。
而每个GC Heap的总大小=Segment占用的空间+LOH
 segment    begin allocated     size
0014d720 790d5588  790f4b38 0x0001f5b0(128432)
013b0000 013b1000  013b3ff4 0x00002ff4(12276)
Large object heap starts at 0x023b1000
 segment    begin allocated     size
023b0000 023b1000  023b3250 0x00002250(8784)
Total Size   0x247f4(149492)
------------------------------
GC Heap Size   0x247f4(149492)
总共的GC堆大概150kb。
---------------------------------------------------------------------------------------------------------
托管线程的内存结构:
这里,简单的交代一下一个托管进程的内存结构。在创建了一个托管的应用程序的线程以后,首先默认情况下创建了最少3个应用程序域,就是系统域,共享域,和默认域。前两个对托管的用户代码来说是不可见的。当时,可以调用共享与中的assemblies。用户的托管代码,和模块被load到默认域中。一个托管的宿主可以根据需要创建一个或者是多个默认域。托管进程,线程(hard thread,soft thread),应用程序域,程序集,模块的关系
托管进程,应用程序域,程序集,模块,这四个概念从左到右是一对多的关系。及一个托管可以对应多个应用程序域,一个appdomain可以对应多个assemblies,一个assembly可以对应多个modules。modules就是我们经常看的.exe或者是.dll。exe文件是windows下对PE文件格式扩展了的托管模块。modules也可以是托管的动态链接库文件。
对于线程,情况有点特殊。这里,首先要区别一个概念,操作系统的进程创建的线程和System.Threading.Thread这个类表示的线程。这里,把操作系统创建的进程叫做hard thread,System.Threading.Thread这个类表示的线程叫做soft Thread。hard Thread和应用程序域的关系,是多堆多的关系。就是一个应用程序域中可以存在多个hard Thread。而一个hard Thread,也可以存在于多个应用程序域里面。而soft Thread,是由应用程序域中的assemblies创建,所以,它只存在于相应的应用程序域中。
当一个系统的hard thread进入某个应用程序域中进行操作的时候,这个应用程序域就会实例化一个System.Threading.Thread类来完成这个线程对应的工作。应用程序域的环境变量属性:
对于每个应用程序域,有一系列的Environment属性可以设置,通过设置这些属性,可以配置一个应用程序域的特性,来满足各种对于安全,性能等许多方面特别的需求。
可以参考MSDN的这里:
http://msdn2.microsoft.com/en-us/library/system.appdomain_properties.aspx
获知应用程序域相关的所有的Properties。
特别说明:应用程序域的动态目录:
对于应用程序域的所有的属性,需要特别提到一个叫做DynamicDirectory 的属性。
这个属性的生成,有两个部分,譬如我本机上面的一个asp.net宿主进程的缓存文件夹:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\mesapplication\8a8504fd\e1680364
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\mesapplication这一部分,由一个叫做DYNAMIC_BASE的属性来定义。同时包含了这个应用程序域中加载的项目文件信息。
后面的两部分8a8504fd\e1680364,根据项目文件的不同,由应用程序的APP_NAME这个属性来决定。
这样何在一起,就构成了在调试的过程中,进程在本机的缓存文件夹。在接下来的下篇中,讲从如何实现的角度,以实例源代码来分析AppDomain的运行机制。