Формат файла .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 |