Как узнать header файла
Заголовок PE (IMAGE_NT_HEADERS) всегда выравнен на границу 8 байт и состоит из трех частей:
Как уже было сказано, заголовок PE всегда начинается с 4-байтовой сигнатуры "PE\0\0" (IMAGE_NT_SIGNATURE). За ней следуют два заголовка: заголовок файла (IMAGE_FILE_HEADER) и необязательный заголовок (IMAGE_OPTIONAL_HEADER). Несмотря на свое название, IMAGE_OPTIONAL_HEADER присутствует в PE-файле всегда (необязательным он является с точки зрения общего формата COFF, поскольку не используется в объектных и библиотечных файлах).
3.2. Заголовок файла
Заголовок файла состоит из 0x14 байтов (определение IMAGE_SIZEOF_FILE_HEADER), размещается сразу после сигнатуры и содержит общее описание файла. Он состоит из следующих полей:
Опишем назначения полей.
Поле Machine
16-битовое число, которое задает архитектуру процессора, на которой может выполняться данная программа. Мне известны следующие коды процессоров (большинство из которых так никогда и не были поддержаны в Windows):
Название | Значение | Процессор |
---|---|---|
IMAGE_FILE_MACHINE_UNKNOWN | 0 | неизвестный процессор |
IMAGE_FILE_MACHINE_I386 | 0x014C | Intel 80386 или выше |
– | 0x014D | Intel 80486 или выше |
– | 0x014E | Intel Pentium или выше |
– | 0x0160 | MIPS R3000, big-endian |
IMAGE_FILE_MACHINE_R3000 | 0x0162 | MIPS R3000, little-endian |
IMAGE_FILE_MACHINE_R4000 | 0x0166 | MIPS R4000 |
IMAGE_FILE_MACHINE_R10000 | 0x0168 | MIPS R10000 |
IMAGE_FILE_MACHINE_WCEMIPSV2 | 0x0169 | MIPS WCE v2 |
IMAGE_FILE_MACHINE_ALPHA | 0x0184 | DEC/Compaq Alpha AXP |
IMAGE_FILE_MACHINE_SH3 | 0x01A2 | Hitachi SH3 |
IMAGE_FILE_MACHINE_SH3DSP | 0x01A3 | Hitachi SH3 DSP |
IMAGE_FILE_MACHINE_SH3E | 0x01A4 | Hitachi SH3E |
IMAGE_FILE_MACHINE_SH4 | 0x01A6 | Hitachi SH4 |
IMAGE_FILE_MACHINE_SH5 | 0x01A8 | Hitachi SH5 |
IMAGE_FILE_MACHINE_ARM | 0x01C0 | ARM |
IMAGE_FILE_MACHINE_THUMB | 0x01C2 | ARM Thumb |
IMAGE_FILE_MACHINE_AM33 | 0x01D3 | Panasonic AM33 |
IMAGE_FILE_MACHINE_POWERPC | 0x01F0 | IBM PowerPC |
IMAGE_FILE_MACHINE_POWERPCFP | 0x01F1 | IBM PowerPC FP |
IMAGE_FILE_MACHINE_IA64 | 0x0200 | Intel IA-64 (Itanium) |
IMAGE_FILE_MACHINE_MIPS16 | 0x0266 | MIPS16 |
– | 0x0268 | Motorola 68000 |
IMAGE_FILE_MACHINE_ALPHA64 | 0x0284 | DEC/Compaq Alpha AXP 64-bit |
– | 0x0290 | HP PA-RISC |
IMAGE_FILE_MACHINE_MIPSFPU | 0x0366 | MIPS with FPU |
IMAGE_FILE_MACHINE_MIPSFPU16 | 0x0466 | MIPS16 with FPU |
IMAGE_FILE_MACHINE_TRICORE | 0x0520 | Infineon TriCore |
IMAGE_FILE_MACHINE_CEF | 0x0CEF | . |
IMAGE_FILE_MACHINE_EBC | 0x0EBC | EFI Byte Code |
IMAGE_FILE_MACHINE_AMD64 | 0x8664 | AMD 64 (K8) |
IMAGE_FILE_MACHINE_M32R | 0x9041 | Renesas M32R |
IMAGE_FILE_MACHINE_CEE | 0xC0EE | . |
Поле TimeDateStamp
32-битовое число, которое содержит дату и время создания данного файла. Формат этого поля недокументирован, однако сборщики Microsoft заносят сюда время как количество секунд от полуночи 01.01.1970 в UTC (т. е. используют юниксовский формат времени, возвращаемого функцией time языка C). Между прочим, это означает, что текущее состояние формата PE действительно только до 18.01.2038 г.
Поскольку формат этого поля недокументирован, некоторые сборщики третьих фирм сохраняют его значение в других форматах. Это может оказаться важным, т. к. данное поле используется при динамическом связывании импорта из DLL.
Поля PointerToSymbolTable и NumberOfSymbols
Согласно стандарту COFF, эти 4-байтовые поля должны обеспечивать доступ к отладочной информации в файле. Однако все известные мне сборщики заносят в них нули, а для доступа к отладочной информации используется иной способ (см. каталог отладочной информации).
Поле SizeOfOptionalHeader
16-битовое число, задающее размер необязательного заголовка. Оно равно 0xE0 для файлов PE32 (IMAGE_SIZEOF_NT_OPTIONAL32_HEADER) и 0xF0 для файлов PE32+ (IMAGE_SIZEOF_NT_OPTIONAL64_HEADER).
Поле Characteristics
16-битовое поле флагов, содержащее COFF-атрибуты файла. Перечислим только те флаги, которые относятся к исполняемым файлам.
3.3. Необязательный заголовок
Необязательный заголовок имеет два различных формата: для PE32 и для PE32+. Соответствующие структуры называются IMAGE_OPTIONAL_HEADER32 и IMAGE_OPTIONAL_HEADER64. Их поля сведены в следующей таблице:
Смещение (hex, PE32/PE32+) | Размер (PE32/PE32+) | Тип (PE32/PE32+) | Название | Описание |
---|---|---|---|---|
00 | 2 | WORD | Magic | Сигнатура заголовка. |
02 | 1 | BYTE | MajorLinkerVersion | Старшая цифра номера версии сборщика. Загрузчиком не используется. |
03 | 1 | BYTE | MinorLinkerVersion | Младшая цифра номера версии сборщика. Загрузчиком не используется. |
04 | 4 | DWORD | SizeOfCode | Сумма размеров всех секций, содержащих програмный код. |
08 | 4 | DWORD | SizeOfInitializedData | Сумма размеров всех секций, содержащих инициализированные данные. |
0C | 4 | DWORD | SizeOfUninitializedData | Сумма размеров всех секций, содержащих неинициализированные данные. |
10 | 4 | DWORD | AddressOfEntryPoint | RVA точки запуска программы. Для драйвера – это адрес DriverEntry, для DLL – адрес DllMain или нуль. |
14 | 4 | DWORD | BaseOfCode | RVA начала кода программы. |
18/– | 4/0 | DWORD | BaseOfData | RVA начала данных программы. Ненадежное поле, загрузчиком не используется. В PE32+ отсутствует! |
1С/18 | 4/8 | DWORD/ULONGLONG | ImageBase | Предпочтительный базовый адрес программы в памяти, кратный 64 Кб. По умолчанию равен 0x00400000 для EXE-файлов в Windows 9x/NT, 0x00010000 для EXE-файлов в Windows CE и 0x10000000 для DLL. Загрузка программы с этого адреса позволяет обойтись без настройки адресов. |
20 | 4 | DWORD | SectionAlignment | Выравнивание в байтах для секций при загрузке в память, большее или равное FileAlignment. По умолчанию равно размеру страницы виртуальной памяти для данного процессора. |
24 | 4 | DWORD | FileAlignment | Выравнивание в байтах для секций внутри файла. Должно быть степенью 2 от 512 до 64 Кб включительно. По умолчанию равно 512. Если SectionAlignment меньше размера страницы виртуальной памяти, то FileAlignment должно с ним совпадать. |
28 | 2 | WORD | MajorOperatingSystemVersion | Старшая цифра номера версии операционной системы. Загрузчиком не используется. |
2A | 2 | WORD | MinorOperatingSystemVersion | Младшая цифра номера версии операционной системы. Загрузчиком не используется. |
2C | 2 | WORD | MajorImageVersion | Старшая цифра номера версии данного файла. Загрузчиком не используется. |
2E | 2 | WORD | MinorImageVersion | Младшая цифра номера версии данного файла. Загрузчиком не используется. |
30 | 2 | WORD | MajorSubsystemVersion | Старшая цифра номера версии подсистемы. |
32 | 2 | WORD | MinorSubsystemVersion | Младшая цифра номера версии подсистемы. |
34 | 4 | DWORD | Win32VersionValue | Зарезервировано, всегда равно 0. |
38 | 4 | DWORD | SizeOfImage | Размер файла в памяти, включая все заголовки. Должен быть кратен SectionAlignment. |
3C | 4 | DWORD | SizeOfHeaders | Суммарный размер заголовка и заглушки DOS, заголовка PE и заголовков секций, выравненный на границу FileAlignment. Задает смещение от начала файла до данных первой секции. |
40 | 4 | DWORD | CheckSum | Контрольная сумма файла. |
44 | 2 | WORD | Subsystem | Исполняющая подсистема Windows для данного файла. |
46 | 2 | WORD | DllCharacteristics | Дополнительные атрибуты файла. |
48 | 4/8 | DWORD/ULONGLONG | SizeOfStackReserve | Размер стека стартового потока программы в байтах виртуальной памяти. При загрузке в физическую память отображается только SizeOfStackCommit байт, в дальнейшем отображается по одной странице виртуальной памяти. По умолчанию равен 1 Мб. |
4C/50 | 4/8 | DWORD/ULONGLONG | SizeOfStackCommit | Начальный размер стека программы в байтах. По умолчанию равен 4 Кб. |
50/58 | 4/8 | DWORD/ULONGLONG | SizeOfHeapReserve | Размер кучи программы в байтах. При загрузке в физическую память отображается только SizeOfHeapCommit байт, в дальнейшем отображается по одной странице виртуальной памяти. По умолчанию равен 1 Мб. Во всех 32-разрядных версиях Windows куча ограничена только размером виртуальной памяти и это поле, по-видимому, игнорируется. |
54/60 | 4/8 | DWORD/ULONGLONG | SizeOfHeapCommit | Начальный размер кучи программы в байтах. По умолчанию равен 4 Кб. |
58/68 | 4 | DWORD | LoaderFlags | Устаревшее поле, не используется. |
5C/6C | 4 | DWORD | NumberOfRvaAndSizes | Количество описателей каталогов данных. На текущий момент всегда равно 16. |
60/70 | 128 | IMAGE_DATA_DIRECTORY[16] | DataDirectory | Описатели каталогов данных. |
Поясним некоторые поля этой структуры.
Поле Magic
16-битовое поле, содержащее сигнатуру заголовка. Может принимать значения:
Название | Значение | Описание |
---|---|---|
IMAGE_ROM_OPTIONAL_HDR_MAGIC | 0x0107 | Заголовок прошивки в ПЗУ ? |
IMAGE_NT_OPTIONAL_HDR32_MAGIC | 0x010B | Заголовок PE32. |
IMAGE_NT_OPTIONAL_HDR64_MAGIC | 0x020B | Заголовок PE32+. |
Поля MajorSubsystemVersion и MinorSubsystemVersion
16-битовые числа, указывающее ожидаемую версию Windows. В отличие от всех остальных полей с номерами версий это поле анализировалось при загрузке программ в NT 4.0 и 95. Если программа была графическим приложением и это поле не содержало версии 4.0, то считалось, что программа разработана для NT 3.51 и моделировалось поведение этой ОС (в частности, отсутствие трехмерных стилей диалогов и пр.). В настоящее время не используется и практически всегда равно 4.0.
Поле CheckSum
32-битовая контрольная сумма файла. Проверяется только в Windows NT при загрузке драйверов ядра и нескольких системных DLL. Алгоритм вычисления контрольной суммы недокументирован, но для ее вычисления можно использовать системную функцию CheckSumMappedFile из библиотеки IMAGEHLP.DLL.
Поле Subsystem
16-битовое число, указывающее в какой подсистеме Windows API должен исполняться данный файл. Его возможные значения:
Название | Значение | Подсистема |
---|---|---|
IMAGE_SUBSYSTEM_UNKNOWN | 0 | Неизвестная подсистема. |
IMAGE_SUBSYSTEM_NATIVE | 1 | Подсистема не требуется, используется драйверами и "родными" приложениями NT. |
IMAGE_SUBSYSTEM_WINDOWS_GUI | 2 | Графическая подсистема Windows. |
IMAGE_SUBSYSTEM_WINDOWS_CUI | 3 | Консольная подсистема Windows. |
IMAGE_SUBSYSTEM_OS2_CUI | 5 | Консольная подсистема OS/2. |
IMAGE_SUBSYSTEM_POSIX_CUI | 7 | Консольная подсистема POSIX. |
IMAGE_SUBSYSTEM_NATIVE_WINDOWS | 8 | "Родной" драйвер Win 9x. |
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI | 9 | Графическая подсистема Windows CE. |
IMAGE_SUBSYSTEM_EFI_APPLICATION | 10 | Программа EFI. |
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER | 11 | Драйвер EFI, обеспечивающий загрузочный сервис. |
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER | 12 | Драйвер EFI времени выполнения. |
IMAGE_SUBSYSTEM_EFI_ROM | 13 | Прошивка ПЗУ для EFI. |
IMAGE_SUBSYSTEM_XBOX | 14 | Подсистема Xbox. |
Поле DLLCharacteristics
16-битовое поле флагов, задающие дополнительные атрибуты файла. Возможные значения флагов:
Название | Значение | Описание |
---|---|---|
IMAGE_DLLCHARACTERISTICS_NO_SEH | 0x0400 | Файл не использует структурную обработку исключений. |
IMAGE_DLLCHARACTERISTICS_NO_BIND | 0x0800 | Запрещает статическое связывание этого файла. |
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER | 0x2000 | Файл является WDM-драйвером. |
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE | 0x8000 | Если этот флаг не установлен, то при загрузке программы терминальным сервером будет загружена вспомогательная DLL, обеспечивающая совместимость кода. |
Поля NumberOfRvaAndSizes и DataDirectory
В конце необязательного заголовка располагается 32-битовое число, в котором хранится количество описателей каталогов данных. За ним следует массив самих описателей, каждый из которых имеет такой вид:
В настоящее время поле NumberOfRvaAndSizes всегда содержит число 16 (символическое имя IMAGE_NUMBEROF_DIRECTORY_ENTRIES). Соответственно массив DataDirectory состоит также из 16 описателей. Каждый описатель содержит RVA и размер для одного каталога данных. Если какого-либо каталога в файле нет, то оба поля его описателя равны нулю.
Каждый из каталогов данных содержит определенную служебную информацию. Вид этой информации определяется номером каталога в массиве описателей. Поскольку каталоги данных, как правило, располагаются внутри секций, для доступа к их содержимому нам потребуется сначала изучить структуру секций.
Все файлы на диске хранятся в виде двоичного (бинарного) кода. Последовательность цифр 1 и 0 определяет содержимое файла. В одном случае эти цифры могут составлять простой текст, в результате чего мы видим обычные текстовые файлы. В другом - это последовательность байт, которая несет самую разную информацию, например: аудио, видео, картинки или закодированный текст. Откройте в текстовом редакторе файлы .TXT и .EXE и вы почувствуете разницу.
В данной статье рассказано каким еще способом (кроме непосредственно расширения файла) можно идентифицировать формат двоичного файла, который не является обычным текстовым. Таких файлов большинство. Именно в них часто есть заголовок файла - это первые несколько байт в определенной последовательности. Часть заголовка может быть одинакова у файлов с одинаковым расширением. Эта часть отвечает за формат файла, для удобства назовем ее «дескриптор заголовка файла» (description с англ. - описание).
Таким образом, если необходимо более точно идентифицировать формат файла или файл переименован и его истинное расширение неизвестно, то узнать что это за файл можно с помощью дескриптора заголовка файла. У нас на сайте дескрипторы представлены в трех видах: HEX, ASCII и ASCII (расширенный). Опишем преимущества каждого представления.
HEX и ASCII. Чтобы определить дескриптор заголовка файла и, соответственно, формат файла, необходима программа, которая представляет файл в виде HEX (шестнадцатеричного кода). Это может быть любой HEX-редактор. Но лучше всего для наших целей подойдет программа MiniDumper (20 Кб).
Скачиваем программу, распаковываем ее, открываем. Далее нажимаем кнопку «Select file…», выбираем файл и видим следующее:
Берем первые 2-3 блока из левой колонки (HEX) или первые символы (точки не учитываем) из правой колонки (ASCII), как показано на рисунке; вводим в соответствующее поле расширенного поиска и получаем результат:
Если расширений найдено много, то можно увеличивать количество блоков до достижения однозначного результата. И наоборот, если Вы ничего не нашли, то следует уменьшить количество блоков.
ASCII (расширенный). ASCII с расширенной таблицей символов - кириллицей и специальными символами. Этот вариант специально создан для ленивых: просто откройте файл с помощью блокнота и ищите первые от начала значащие символы. Например:
Далее, вставляем эти символы в соответствующее поле расширенного поиска и получаем результат:
Обращаем ваше внимание, что наиболее точным и продуктивным из всех трех вариантов будет поиск по HEX-декскрипторам, т.к. некоторые последовательности байт невозможно перевести в корректный ASCII-код и HEX-значения мы берем точно из начала файла.
Скорее всего, вы знаете, что при открытии страницы любого сайта происходят действия на сервере, которые не видны пользователям. Однако эти данные обрабатывают поисковые системы. И к счастью, некоторые из этих данных поддаются корректировке, и мы немного можем облегчить работу веб-сервера.
- Клиент устанавливает TCP-соединение (или соответствующее соединение, если транспортный уровень не является TCP).
- Клиент отправляет свой запрос и ждёт ответа.
- Сервер обрабатывает запрос, отправляя ответ обратно, предоставляя код состояния и соответствующие данные.
Этот заголовок может содержать инструкции, которые клиенты и поисковые системы могут использовать для правильной обработки URL.
X-Robots-Tag
Это аналог метатега robots в html. У данного элемента есть преимущества над meta name=“robots”. Например, если вы хотите запретить к индексации файлы PDF, метатег robots не поможет, так как он не работает с PDF-файлами. Вместо этого, вы можете использовать заголовок X-Robots-Tag.
К тому же у X-Robots-Tag есть ещё одно преимущество – его легко настраивать для целых каталогов и папок, что может ускорить работу.
Помимо «noindex» и «nofollow», вы можете прописать другие ответы X-Robots-Tag. Директивы из справки Google — ссылка:
Canonical
Hreflang
Cache-control
Cache-control может влиять на то, как браузер кэширует страницу и связанные с ней ресурсы. Например, вы можете предоставить ответ «max-age», который сообщает браузеру, что через некоторое время страница должна быть повторно запрошена с сервера. В противном случае кэш страницы действителен то время, которое указано в значении «max-age», тем самым ускоряя скорость загрузки страницы. Директивы из справки Google — ссылка:
Служит для определения различий отображения контента для ПК и мобильных устройств. Особенно это важно для сайтов, которые используют динамический показ для мобильных пользователей. Для сайтов с адаптивным дизайном данный элемент не так актуален.
При правильной настройке заголовка Vary поисковые боты будут сканировать сайт со всеми указанными типами User-agent и определять, какая версия кода будет ранжироваться для какого типа пользователей.
Last-Modified
If-Modified-Since
Это условный запрос, который передаёт объект, если он был изменен после указанной даты. То есть передаются данные только в том случае, когда кэш устарел.
If-Unmodified-Since
Это условный запрос, который передаёт объект, только если он не был изменен после указанной даты.
Expires
Дата/время, после которого ответ веб-сервера считается устаревшим. Например, можно указывать текущую дату + 7/10/14 дней.
Accept-Encoding
Content-Encoding
Content-Length
Размер ресурса в десятичном числе байтов.
Content-Type
Указывает тип носителя ресурса.
Location
Указывает URL-адрес для перенаправления страницы. Он используется только тогда, когда для пользователя указывается перенаправление на другую страницу (3xx код) или при новом местоположении ресурса (201 код).
После чего выбрать вкладку «Network» и обновить страницу (F5).
Далее в графе «Name» необходимо выбрать тип файла, для которого вы хотите проверить заголовки, и справа во вкладке «Headers» будут указаны все заголовки текущего файла.
Аналогичным способом можно проверить заголовки и в Firefox: при помощи Ctrl+Shift+C либо в верхнем выпадающем меню выбрать «Веб-разработка»→«Инструменты разработчика». Далее выбрать вкладку «Сеть» и обновить страницу (F5). После чего выбрать тип документа для проверки и в правой части экрана выбрать вкладку «Заголовки». Перед вами появятся заголовки текущей страницы.
Примеры популярных расширений:
Также в сети есть большое количество онлайн-программ, при помощи которых вы можете проверить заголовки своего сайта:
В заключение
Имена программных элементов, таких как переменные, функции, классы и т. д., должны быть объявлены, прежде чем их можно будет использовать. Например, нельзя просто писать x = 42 без предварительного объявления "x".
Объявление сообщает компилятору, является ли элемент int , a double , функцией class или другим элементом. Кроме того, каждое имя должно быть объявлено (прямо или косвенно) в каждом cpp-файле, в котором он используется. При компиляции программы каждый CPP-файл компилируется независимо в единицу компиляции. Компилятор не имеет сведений о том, какие имена объявляются в других единицах компиляции. Это означает, что если вы определите класс или функцию или глобальную переменную, необходимо предоставить объявление этого объекта в каждом дополнительном cpp-файле, который его использует. Каждое объявление этого элемента должно быть точно одинаковым во всех файлах. Небольшая несогласованность вызовет ошибки или непреднамеренное поведение, когда компоновщик пытается объединить все единицы компиляции в одну программу.
в Visual Studio 2019 функция модулей c++ 20 появилась в качестве улучшения и в конечном итоге заменяет файлы заголовков. Дополнительные сведения см. в разделе Общие сведения о модулях в C++.
Пример
В следующем примере показан общий способ объявления класса и его использования в другом исходном файле. Начнем с файла заголовка, my_class.h . Он содержит определение класса, но обратите внимание, что определение не завершено; Функция-член do_something не определена:
В файле реализации при необходимости можно использовать using оператор, чтобы не указывать каждое упоминание "my_class" или "cout" с "N::" или "std::". Не помещайте using операторы в файлы заголовков!
После того как компилятор завершит компиляцию каждого CPP-файла в OBJ-файлы, он передает OBJ-файлы компоновщику. Когда компоновщик объединяет объектные файлы, обнаруживается только одно определение для my_class; Он находится в OBJ-файле, созданном для my_class. cpp, и сборка выполняется.
Включить условия
Что следует разместить в файле заголовка
Поскольку файл заголовка потенциально может включаться в несколько файлов, он не может содержать определения, которые могут формировать несколько определений с одним и тем же именем. Следующие действия не разрешены или считаются очень неправильными.
- встроенные определения типов в пространстве имен или глобальной области
- невстроенные определения функций
- определения неконстантных переменных
- агрегатные определения
- безымянные пространства имен
- Директивы using
Использование using директивы не обязательно приведет к ошибке, но может вызвать проблему, так как она переводит пространство имен в область каждого CPP-файла, который напрямую или косвенно включает этот заголовок.
Пример файла заголовка
В следующем примере показаны различные виды объявлений и определений, допустимых в файле заголовка.
Читайте также: