开发者社区> 吞吞吐吐的> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

元数据与IL简介

简介:
+关注继续查看

文/玄魂

1.3.2       元数据

元数据是描述数据的数据。在CLR的上下文中,元数据表示由描述符组成的一套体系,这些操作符包括了在一个模块中被声明或引用的所有项。由于CLR模型是面向对象的,因此在元数据中描述的项是类和它们的成员,以及它们伴随着的特性、属性和关联。本节简单地介绍元数据,与原数据安全相关的内容会在后续章节中继续讲解,元数据的详细内容不在本书的论述范围之内。

元数据实际上是一块二进制数据,包含了三种表:定义表、引用表和清单表。

元数据定义表主要是模块定义、类型定义、方法定义、字段定义、事件定义、参数定义、属性定义等一系列定义表的集合。当编译器编译代码时,所有定义的内容都会生成对应的定义表。

元数据引用表用于记录编译器中源代码引用的类型、方法、字段、事件。常用的引用表如:AssemblyRef(程序集引用表)、ModuleRef(模块引用表)、TypeRef(类型引用表)等。

元数据清单表包含了组成程序集所需要的所有信息,同时包含了对其他程序集的引用信息。它明确地指出了哪些条目可以对外开放,哪些条目只可以在程序集内部进行访问。

下面通过经典的HelloWorld程序简要分析其中的元数据信息,如代码清单1-7所示。

代码清单1-7 HelloWorld程序代码

复制代码
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace HelloWorld

{

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("Hello World!");

            Console.Read();

 

        }

    }

}
复制代码

 

下面使用反汇编工具ILDasm打开HelloWorld.exe,双击MANIFEST,图1-7为查看清单信息的截图。ILDasm的使用方法和参数说明请读者参考MSDN文档。

 

图1-7  查看程序清单信息

详细的清单信息如代码清单1-8所示。

代码清单1-8 HelloWorld.EXE的清单信息

复制代码
// Metadata version: v4.0.21006

.assembly extern mscorlib

{

  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..

  .ver 4:0:0:0

}

.assembly HelloWorld

{

......

}

  .hash algorithm 0x00008004

  .ver 1:0:0:0

.module HelloWorld.exe

// MVID: {B8EB35DD-5AD2-402C-B422-AA63B0AACCFA}

.imagebase 0x00400000

.file alignment 0x00000200


.stackreserve 0x00100000

.subsystem 0x0003       // WINDOWS_CUI

.corflags 0x00000003    //  ILONLY 32BITREQUIRED

// Image base: 0x05C40000
复制代码

 

程序比较简单,代码中包含了版本、外部引用等简单的信息。表1-2描述了示例中所使用的 HelloWord.exe 程序集的程序集清单中的各项指令。

表1-2 HelloWorld.exe指令说明

指令

说明

.assembly extern <assembly name >

指定包含当前模块所引用项目的另一程序集(在此示例中为 mscorlib)

.publickeytoken < token>

指定所引用程序集的实际密钥的标记

.ver < version number >

指定引用程序集的版本号

.assembly < assembly name >

指定程序集名称

.hash algorithm < int32 value >

指定使用的哈希算法

.module < file name >

指定组成程序集的模块名称,在此示例中,程序集只包含一个文件

.subsystem < value >

指定程序要求的应用程序环境。在此示例中,值 3 表示该可执行文件从控制台运行

.corflags

当前是元数据中的一个保留字段

根据程序集的内容,程序集清单可包含许多不同的指令。有关程序集清单中指令的完整列表请读者参考相关文档,本例旨在抛砖引玉。若要查看完整的元数据信息,可以使用快捷键“Ctlr+M”,如图1-8所示。

 

图1-8 查看元数据信息

1.3.3       IL常用指令

为方便起见,还是以HelloWorld.exe为例讲解IL的相关内容。由于篇幅所限,关于IL的详细内容还请各位读者参考相关资料。图1-9为Main方法的IL代码。

 

图1-9 HelloWorld.exe Main方法的IL代码

在一个中间语言程序中,如果某一行以“.”开始,代表这是一个传输给汇编工具的指令;而没有以“.”开始的行是中间语言的代码。上图中.method是方法定义指令,定义了Main方法,参数在“()”中,IL代码在“{}”中。.entrypoint是入口指令,表明该方法是入口方法。.maxstack指定了最大栈的深度为8。下面的IL_n是代码标签,后面是IL代码。nop是空指令;ldstr指令向栈中压入字符串“Hello World!”;call指令调用静态方法Console.WriteLine(string)和Console.read();pop弹出栈顶的值;ret指令表示方法体的结束。IL支持“//”和“/* */”的注释方法。

提示  在中间语言中,如果需要调用一个方法,需要指定方法的全名,包括它的名称域(namespace)、类名、返回值类型和参数的数据类型。

表1-3列举了IL的其他一些常用指令,更多的指令可以查看IL指令表。

表1-3 IL常用指令

指令

描述

.assembly <程序集名称> {}

设置程序集

ldc.i4.n

把一个 32位的常量(n从0到8)装入堆栈

stloc.n

把一个从堆栈中返回的值存入第n(n取0~8)个局部变量

add

2个值相加。命令的参数必须在调用前装入堆栈,该函数从堆栈中移除参数并把运算后的结果压入堆栈

sub

2个值相减

mul

2个值相乘

newarr type

生成一个元素类型为type 的数组。数组的大小必须在调用该命令前装入堆栈。该命令会把一个数组的引用装入堆栈

stelem.i4

给一个数组成员赋值。数组的引用、下标和值必须在调用该命令前装入堆栈

ldelema type

把数组元素的地址装入堆栈。数组的引用和下标必须在调用该命令前装入堆栈。地址用来调用非静态函数

ldlen

把数组的长度装入堆栈。数组的引用必须在调用该命令前装入堆栈

ldloca.svariable

把变量的地址装入堆栈

ldc.i4.s value

把一个Int32的常量装入堆栈(用于大于8位的数)

conv.i4

把堆栈中值转换成Int32类型

call instancefunction(arguments)

调用类的非静态函数

bge.s label

跳转至label 如果value1≥value 2. Values 1和 2 必须在调用本命令前装入堆栈

br.s label

跳转至label

box value type

把一个值类型转成一个Object,并把该Object的引用装入堆栈

blt.s label

跳转至label 。如果value 1小于 value 2. Values 1 和 2 必须在调用本命令之前装入堆栈

ldelem.i4

把一个数组元素装入堆栈。数组引用和下标必须在调用本命令之前装入堆栈

ldarga.sargument

把函数参数的地址装入堆栈

dup

在堆栈上复制一个值

stind.i4

存储值的地址。地址和值必须在调用本命令之前装入堆栈

.field

定义类成员。和关键字public、private、static等一起使用

stsfld static field

用堆栈中的值替换静态字段的值

ldfld field

把一个非静态字段装入堆栈。类实例的地址必须在调用本命令之前装入堆栈

ldarg.n

把第n个参数装入堆栈。在非静态函数中,第0个参数是一个隐含的参数,代表this

newobjconstructor

用构造函数constructor生成一个类的实例。构造函数的参数必须在调用本函数之前先装入堆栈。一个类的实例会被生成并装入堆栈

callvirt instancefunction

调用一个对象的后期绑定方法

 

1.3.4       IL与代码验证

在将MSIL编译为本机代码的过程中,MSIL代码必须通过验证过程,除非管理员已经建立了允许代码跳过验证的安全策略。验证过程检查MSIL和元数据以确定代码是否是类型安全的,这意味着它仅访问已被授权访问的内存位置。类型安全帮助将对象彼此隔离,因而可以保护它们免遭无意或恶意的破坏。它还提供了对代码可以可靠地强制安全限制的保证。

运行库使用下列条件来验证代码是否为类型安全:

q  对类型的引用与被引用的类型严格兼容。

q  在对象上只调用正确定义的操作。

q  标识与声称的要求一致。

验证过程中检查 MSIL 代码,尝试确认该代码只能通过正确定义的类型访问内存位置和调用方法。例如,代码不允许以超出内存范围的方式来访问对象。另外,验证过程检查代码以确定 MSIL 是否已正确生成,这是因为不正确的 MSIL 会导致违反类型安全规则。验证过程通过正确定义的类型安全代码集,并且它只通过类型安全的代码。然而,由于验证过程存在一些限制,某些类型安全代码可能无法通过验证,而某些语言在设计上并不产生可验证的类型安全代码。如果安全策略要求提供类型安全代码,而该代码不能通过验证,则在运行该代码时将引发异常。

-------------------------注:本文摘抄自《.NET 安全揭秘》1.3节


本文转自悬魂博客园博客,原文链接:http://www.cnblogs.com/xuanhun/archive/2012/05/24/2516346.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
数据劫持
对属性的读取和修改拦截简单来说就是数据的任何变化都要能监测到,这样才能根据数据变化做对应操作
174 0
元数据
元数据概述:元数据是一种二进制信息,用以对存储在公共语言运行库可移植可执行文件 (PE) 文件或存储在内存中的程序进行描述。将您的代码编译为 PE 文件时,便会将元数据插入到该文件的一部分中,而将代码转换为 Microsoft 中间语言 (MSIL) 并将其插入到该文件的另一部分中。
901 0
云简介
引用:http://blog.csdn.net/hmg25/article/details/7161066 对于云计算,李开复(现任Google全球副总裁、中国区总裁)打了一个形象的比喻:举个例子,如果你有一笔钱需要管理,那么,最简单易行的方式是把钱塞在自己的枕头底下,然后在小本本上记下每一笔入账和花销。
1131 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载