MS.Net CLR 扩展PE结构分析2

Flier Lu <flier_lu@sina.com.cn>
  
注意:本系列文章在水木清华BBS(smth.org)之.Net版首发,
     转载请保留以上信息,发表请与作者联系
  
Metadata 篇
  
第一章 Metadata 概述
  
1.1 什么是 Metadata
  
    Metadata翻译成中文是“元数据”,可以理解为Type of Type,
说白了就是描述类型的类型数据。从最初级的语言层面支持的RTTI
(“近代”的编程语言基本上都提供了足够的支持,如C++,Delphi等,
部分较“落伍”的语言也通过不同形式如扩展库提供了模拟支持,
“现代”的编程语言则提供了强力的支持,如Java和C#<本质是CLR>),
到后来二进制级的COM的IDL和类型库(类型库是IDL编译后的二进制形式),
到现在的Metadata,其实是遵循着相同的设计思路。只是出于不同的需求
设计、实现,有这各自的优点缺点罢了。但随着语言的发展,更多的需求集中在
灵活性方面,因而语言发展的趋势是元数据的使用越来越多、支持越来越强。
    举个最简单的例子,在IDE中,动态显示当前对象的方法、属性名列表的功能
(MS叫IntelliSense,Borland叫CodeInsight),就得宜于类型信息
以前在VC里实现,比较麻烦,得生成专门的符号库;在VB里强一点,可以通过
COM的IDispatch,ITypeInfo,ITypeLib等接口动态获取,但编程麻烦要死;
到CLR,库一级直接提供支持,可以通过System.Reflection完全控制
甚至比COM类型库更高一级地支持动态创建。
   对用户来说,可以完全了解当前程序接口,有哪些Module,哪些Class,
哪些Method等等,这给开发者提供了巨大的创造空间。如DUnit(DotNet下
的XUnit单元测试平台)就大量使用Reflection机制,我们等会谈使用时再说。
  
1.2 Metadata在CLR中的作用
  
    对于CLR架构来说,Metadata可以算是核心操作对象,几乎绝大多数功能
都需要参考其数据。从静态的IL代码构成(二进制编码中直接使用Metadata里的Token)
到动态JIT编译器(使用Metadata定位IL代码及其关系);从简单的代码载入执行
(Class Loader通过Metadata定位代码入口、编译执行)到复杂的不同语言互操作
(如VB.Net继承C#的类,实际上是直接继承CLR中Metadata中的类);等等……
几乎所有地方都能看到Metadata的身影。
  
    因为本文的主要目的是介绍底层结构,这里就不再罗嗦Metadata的好处了,
反正以后文章中大家会次次看到他,各种优点自己慢慢体会吧 :)
  
1.3 如何访问和使用 Metadata
  
   做了一通广告,大家一定很关心如何使用Metadata,听我慢慢道来
   在CLR里使用Metadata,可以在三个层面进行操作。
   最简单的方法是直接通过类库提供的System.Reflection命名空间中的
若干类进行访问,例如
  
using System.Reflection;
using System;
  
public class Simple
{
    public static void Main ()
    {
         Module mod = Assembly.GetExecutingAssembly().GetModules () [0];
         Console.WriteLine ("Module Name is " + mod.Name);
         Console.WriteLine ("Module FullyQualifiedName is " +
mod.FullyQualifiedName);
         Console.WriteLine ("Module ScopeName is " + mod.ScopeName);
    }
}
  
   这种访问方式使用起来最简单,功能也足够强大,能够完成我们绝大多数的需要,
特别是在System.Reflection.Emit命名空间中,更提供了动态生成、修改的支持
功能强大得我都想不出能有什么改进了 :) (写.Net病毒就靠他了,hoho)
   不过这种方式必须有CLR环境的支持,受到库功能的限制(后面我们会看到很多
在Reflection一级里不提供的信息:),因此MS为工具软件开发商提供了另一套
较底层的开发库,Metadata Unmanaged API。这套库通过一系列COM接口,
提供了直接访问Metadata的强大支持,System.Reflection应该就是使用它实现的。
有兴趣的朋友可以参看FrameworkSDK\Tool Developers Guide\docs
目录下的Metadata Unmanaged API.doc文档,里面有详细的说明。
如同其名字所示,它必须用Unmanaged代码来使用,如传统的VC,Delphi等。
   可以说99%的工作,都可以通过上面两套库来完成,不过总有些象我这样的人,
喜欢对技术追根究底,想把隐藏在美好面纱下的底层架构纠出来暴露一把,呵呵
因此有了第三个层面,二进制层面的逆向工程分析。
   好在MS为了让其CLI(CLR的子集)标准化,公开了大量文档,总算没要我用上
SoftIce之类的牛刀,Partition II Metadata.doc文档中对Metadata的
二进制格式实现给出了比较详尽的说明,加上GNOME的mono项目已经做了很多工作
因而对Metadata的二进制层面分析不是那么困难。
   接下去的文章中,我会逐渐将Metadata在PE中的组织结构逐渐剥离开来,
让大家能够了解这个神秘的CLR核心到底是什么,里面隐藏了些什么,我们能够通过
他做什么,为什么要这样设计,等等……
  
1.4 Metadata在PE中的组织结构
  
   说了一通废话后,回到正体上来,谈谈Metadata在PE中的组织结构。
  
注意:这一章里面我只把Metadata结构的大概情况介绍一下,下一章会专门
针对二进制模式分析进行详细讲解。如果你只想了解底层结构,可以跳过
下一章。以后的文章也会遵循这种方式组织,讲一些结构、原理,跟着讲
一些实际数据分析方法。
  
   上次我们提到CLR的头信息里面专门有一个字段指向Metadata数据块,
实际上这个数据块只是Metadata的一个头结构,保存有Metadata的信息,
而Metadata的实际数据,是通过若干不同的Heap或者说Stream保存的。
这里我统一使用Stream“流“作为他的名字,但很多文档中以Heap”堆“作为
其称呼,我们可以理解他是一个二进制流,其中数据以堆的结构进行组织。
   Metadata里最常见的有五种流,#String, #Blob, #Guid,
#US(User String)和#~流("#"是流名字的前缀)
   String流就是一个字符串堆,Metadata内部用到的所有字符串如类或方法
的名字等等都以UTF8编码保存在此堆内。而用户的字符串如字符串常量,
则以Unicode编码保存在US(User String)堆内。值得注意的是,
US流和String流在二进制结构组织上不同,我们后面将分析时会详细提及。
Guid流是保存程序中使用到的Guid的数组,如Assembly中Module的MVID。
Blob流是一个通用存储空间,除了Guid和字符串以外基本上所有
乱七八糟的东西都放在里面,呵呵,如PublicKey,常量的值等等。
   最重要的是#~流,这是Metadata实际信息存放的地方。#~流结构上以
若干张表(Table)的形式组织,每张表存储某一方面的Metadata信息,
如MethodDef表存储所有方法的信息。每张表又由若干的行(Row)组成
每行有n个列(Column),每列代表一种信息,如MethodDef表中每一行
都有一个方法的RVA,类型标志,名字,Signature等等信息。在其中通过
各种索引来相互关联,整个组织结构和关系数据库很相似。
   比较特殊的是,这里所有的表通过一个64bit的有效位图来表示其存在与否
每种类型的表有一个编号,如MethodDef表的编号是6,则第(1<<(6-1))位置1
因而每个表的每一行,可以使用一个唯一的Token表示。此Token是一个32bit
无符号整型数,最高一个字节表示表的编号,低三个字节表示表中的索引号。
如0x06000003表示0x06表(MethodDef)中第3行(如MyApp::Add)
这个Token概念在CLR中频繁使用,如IL代码调用函数、使用变量都是使用Token。
   与之类似的还有Coded Index,下次讲二进制实现时再说。 

时间: 2024-11-03 20:50:14

MS.Net CLR 扩展PE结构分析2的相关文章

MS.Net CLR 扩展PE结构分析(转,很不错的文章)

Flier Lu <flier_lu@sina.com.cn>   注意:本系列文章在水木清华BBS(smth.org)之.Net版首发,      转载请保留以上信息,发表请与作者联系   概述       本系列文章,将从系统层角度,通过对MS.Net CLR架构对PE映像结构的扩展的分析 , 解析MS.Net CLR架构的底层部分运行机制,帮助读者从更深层次理解CLR中某些重要概念 本文读者应具备基本的Win32编程经验,了解.Net中常见概念意义,并对Win32之PE映像 结构有一定了

CLR 扩展存储过程 如何返回值

问题描述 网上关于CLR扩展存储过程的源码都是C#的,C#可以用refstringxxxx来返回一个值,如果用VC++,不知道如何设置返回参数C#:......staticvoidstorepe(sqlstringa,sqlstingb,refsqlstringc)...sql新建查询...execsp'aaa','bbb',@outstringOUTPUTselectoutstringasOUTPUT_PARAM...这样可以再SQL中看到返回的C的值C++:但是如果用C++来写的话,这个返回

.Net平台下CLR程序载入原理分析

程序 Flier Lu <flier_lu@sina.com.cn>   注意:本系列文章在水木清华BBS(smth.org)之.Net版首发,      转载请保留以上信息,发表请与作者联系     与传统的Win32可执行程序中的本机代码(Native Code)不同, 微软推出的.Net架构中,可执行程序的代码是以类似Java Byte Code的 IL (Intermediate Language)伪代码形式存在的.在.Net可执行程序载入后, IL代码由CLR (Common Lan

利用MS AJAX 扩展服务器端控件

ajax|服务器|控件 通过MS AJAX可以扩展一个服务器端控件在客户端呈现后的特性,使其界面更加友好.        实例代码:IScriptControl.rar         一.创建网站,选择ASP.NET AJAX-Enabled Web Site.        二.向项目中添加一个类,使其派生自TextBox,并实现IScriptControl接口.如下代码实例: public class SampleTextBox : TextBox, IScriptControl     

利用MS AJAX扩展服务器端控件

通过MS AJAX可以扩展一个服务器端控件在客户端呈现后的特性,使其界面更加友好.实例代码:IScriptControl.rar 一.创建网站,选择ASP.NET AJAX-Enabled Web Site.二.向项目中添加一个类,使其派生自TextBox,并实现IScriptControl接口.如下代码实例: public class SampleTextBox : TextBox, IScriptControl 三.这个控件我们将实现两个属性:HighlightCSSClass 控件得到焦点

Javascript数组常用方法[包含MS AJAX.NET的prototype扩展方法]示例

看了JefferyZhao的MSDN web cast视频教程,亲自实践了一下,代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "

Windows PE入门基础知识:Windows PE的作用、命名规则、启动方式、启动原理

Windows PE的全名是WindowsPreinstallationEnvironment(WinPE)直接从字面上翻译就 是"Windows预安装环境".微软的本意是:WinPE仅用做系统维护,并设置了各种限制.可以简单的理解为:PE是Windows系统的超级精简版.超级权限版(以系统system账户登录)!对于无法进入系统.修复系统.分区.重装系统等问题都可以进入PE进行操作,因此PE是系统维护强大的武器!   微软原版的PE,只有"命令行"即DOS窗口.网

.Net远程方法调用研究

简介远程方法调用发展到现在,已经有以下几种框架实现:DCE/RPC,CORBA,DCOM,MTS/COM+,Java RMI,Java EJB,Web Services/SOAP/XML-RPC,NET Remoting,本文主要介绍了.NET远程方法调用的原理,实现以及与微软COM/DCOM实现的异同点. 框架Microsoft .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架.众所周知,Web服务仅仅提供了一种简单的容易理解的方法来实现跨平台,跨语言的交互

.Net开发平台研究(二)

类库主要的好处是它们将核心Win32 API的最常用的功能和外挂SDK的功能封装到了一个统一的包中.采用清晰而有条理的方式对类库进行了分组和描述,这样开发者能更容易地找到他们的应用程序所需的大多数功能. 相反,在过去几年中,新功能要么被"绑缚"到Win32 API上,要由通过独立的API(例如用于图形的Directx,或者用于XML和SOAP的不同的SDK)来提供.对它们唯一能做的逻辑分组就是按照字母顺序进行排序.结果,使用Win32 API和各种SDK经常使人晕头转向,而开发者必须判