Visual Studio编译器如何将安全属性编译为CIL?

时间:2013-12-24 01:12:40

标签: c# cil il ildasm ilasm

我的班级中的方法有以下属性SecurityPermission(SecurityAction.Assert)。我编译它(调试版本)并通过查看原始堆并查看包含PermissionSet blob的blob堆来查看ildasm.exe中的输出。我期望(根据ECMA-335):

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  00 00

但我看到的是:

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  01 00

请特别注意我预期01 00末尾的00 00。规范说,计数后的字符串应该是命名参数的数量。由于我没有传递任何命名参数,我预计该数字为16位0。

这是使用Visual Studio 2013针对.NET 2.0编译的。

更复杂的是,如果我添加一个命名参数,我得到这个:

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  12 01 54 02 0d 55 6e 6d >1934e089  T  Unm<
61 6e 61 67 65 64 43 6f  64 65 01                >anagedCode      <

再一次,查看属性的计数字符串的结尾,您可以看到12 01后跟命名参数列表(一个项目的列表)。我希望这是01 00,一个16位的小端1,用于命名参数的数量。

基于此,我假设计数字符串后面的第二个字节是命名参数计数,但我仍然不明白第一个字节是什么(第一个例子中是0x01,下一个是0x12)。

如果我添加第二个命名属性,则第一个字节更改为26,如果我添加第三个命名属性,则更改为33.我没有看到数字的明显模式,而不是它们正在增加的事实

我问的是这个问题,因为我正在尝试手工构建一个PermissionSet blob(我正在编写一个CLR探查器),我需要知道该字节中要放什么。

1 个答案:

答案 0 :(得分:1)

我认为你的沮丧是正确的,我记得我以前对命名参数的经验 - NumNamed是作为压缩的int实现的,而不是规范中陈述的int16,并且与给出的示例不同VI.B.3。我不知道在后续的.NET 3.0+实现中是否已经改变了。

对于您正在寻找的 PermissionSet

  

...    *一组属性,编码为自定义的命名参数   属性将是(如§II.23.3,从NumNamed开始)。

     

...   §II.23.3   ...

     

接下来是对可选“命名”字段和属性的描述。   这从NumNamed开始 - 一个unsigned int16给出的数字   “命名”属性或后面的字段。 ... 在这种情况下   NumNamed非零,其后是NumNamed重复   NamedArgs。

12 01是小端整数“给出后面的属性数”。一个命名属性,总长度为18(十进制,包括在内)。

这个总长度是你正在寻找的模式,但要注意,因为我认为这个长度是可选的,有时编译器设法在前面的int16中打包属性的数量,丢弃长度。您将不得不尝试使用不同数量的属性来确保正确解析所有情况。

  

NamesArgs:

     

... SerString - PackedLen字节数,后跟UTF8   字符

     

PROPERTY是单字节0x54。 FieldOrPropName是其名称   字段或属性,存储为SerString(上面定义)