Формат файла .NET – внутреннее устройство сигнатур (часть 1) - Сигнатуры

ОГЛАВЛЕНИЕ

4. Сигнатуры

Почти все приготовления завершены, и можно начинать рассматривать сигнатуры, но стоит упомянуть еще несколько вещей, не очевидных для всех. Первое – почти все целые числа в сигнатурах сжаты. Второе – все сигнатуры начинаются с размера (в байтах), занимаемого ими в куче #Blob, разумеется, это значение хранится с использованием сжатия целых. Наконец, что не менее важно, значения, показывающие местоположение сигнатуры в куче #Blob, абсолютные, т.е. вам не нужно ничего прибавлять/отнимать от основного значения (так, как в красном круге (на рисунке) на рисунке 1), чтобы найти сигнатуру в куче.

Заметьте, что когда вы перекомпилируете прикрепленный исходный код (даже не изменяя его), сигнатуры в получаемой сборке могут изменить смещение.

Так как данная статья – скорее руководство, в данном разделе по байтам рассматриваются все сигнатуры, начиная с простейших и заканчивая самыми сложными. Каждая рассматриваемая сигнатура связана с описанием, диаграммой или синтаксисом, скопированным из спецификации, и набором примеров, полные двоичные файлы и исходники которых можно загрузить вверху данной статьи, по возможности приложения написаны с помощью C#, в ином случае – с использованием CIL (раньше MSIL).

4.1 FieldSig

Как сказано выше, мы начинаем с простейших сигнатур. Одна из них - сигнатура FieldSig, она в основном описывает тип поля и специальные модификаторы, прикрепленные к полю, проиндексирована столбцом Field.Signature. Конечно, сигнатура поля начинается с размера всей сигнатуры, следующим идет пролог FIELD, имеющий постоянное значение 0x6, ноль или больше специальных модификаторов, и тип поля. Схема синтаксиса для FieldSig показана ниже на рисунке 2
Замечание: не путайте специальные модификаторы со специальными атрибутами! Это абсолютно разные вещи. Так как специальные модификаторы образуют часть нескольких сигнатур, они будут рассмотрены в следующем разделе. В примерах данного раздела никакие специальные модификаторы не используются.



Рисунок 2. Схема синтаксиса сигнатуры FieldSig

Пример 1

Этот пример вполне понятный: создается простое поле типа int32, как показано ниже.

// Полный исходник: FieldSig\1.cs 
// Двоичный файл: FieldSig\1.dll
// (...)

public int TestField;

Теперь нужно загрузить двоичную сборку FieldSig\1.dll в проводник CFF и перейти в таблицу Field, чтобы найти строку, связанную с нашим полем (должна быть только одна). Рисунок ниже должен помочь вам.

 

Рисунок 3. Строка поля TestField в таблице метаданных Field

Мы нашли ее! Переходим на 0x000A в #Blob.

Рисунок 4. Сигнатура FieldSig, просматриваемая программой проводник CFF

Теперь разберем сигнатуру по байтам в таблице ниже.

Смещение

Значение

Что означает

0x0A

0x02

Размер сигнатуры

0x0B

0x06

Пролог

0x0C

0x08

Значение типа поля int32, смотрите константы

Пример 2

В этот раз мы меняем тип поля на string (строка), как показывает следующий листинг кода.

// Полный исходник: FieldSig\2.cs 
// Двоичный файл: FieldSig\2.dll
// (...)

public string TestField;

Сигнатура FieldSig для поля TestField все еще находится в 0x000A, и только последний байт изменился с 0x08 на 0x0E.

Смещение

Значение

Что означает

0x0A

0x02

Размер сигнатуры

0x0B

0x06

Пролог

0x0C

0x0E

Значение типа поля string, смотрите константы