HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2

ANTICHAT — форум по информационной безопасности, OSINT и технологиям

ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию. Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club, и теперь снова доступен на новом адресе — forum.antichat.xyz.
Форум восстановлен и продолжает развитие: доступны архивные темы, добавляются новые обсуждения и материалы.
⚠️ Старые аккаунты восстановить невозможно — необходимо зарегистрироваться заново.
Вернуться   Форум АНТИЧАТ > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Безопасность и Анонимность > Защита ОС: вирусы, антивирусы, файрволы.
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 25.04.2026, 15:38
Marylin
Постоянный
Регистрация: 01.09.2019
Сообщений: 378
Провел на форуме:
145166

Репутация: 0
По умолчанию

В программинге существует много деталей, которые отделяют любительскую поделку от профессионального софта. Одной из таких деталей является манифест приложения - XML-файл, который управляет тем, как ОС взаимодействует с программой. В Visual Studio и других IDE этот файл добавляется парой кликов мыши. Но как быть, если мы пишем на чистом ассемблере? В отличие от распространённого мнения, fasm предоставляет элегантные механизмы для встраивания манифестов. Более того, работа с ними на ассме даёт нам полный контроль над каждым байтом ресурсов. В этой статье мы разберём, что такое манифесты, зачем они нужны, и как правильно встраивать их в наши проекты.

1. Введение
2. Ресурс RT_MANIFEST
3. Информация о версии VERSIONINFO
4. Реализация на практике
5. Под занавес

1. Введение

Манифест - это XML, который встраивается в исполняемый EXE/DLL в качестве ресурса. ОС читает этот файл при запуске программы, чтобы определить её поведение. Представьте манифест как паспорт вашей программы. В нём указано:

1. Кто вы (идентификатор сборки)
2. Что вам нужно (зависимости от библиотек элементов управления comctl32.dll)
3. Какие у вас права (требуется ли запуск от имени админа)
4. С какой версией Win вы совместимы (важно для корректной работы таких функций как GetVersionEx).

При отсутствии манифеста ОС считает, что перед ней стандартная программа для XP, и применяет к ней устаревшие правила поведения. Именно из-за отсутствия правильного манифеста многие ASM-программы выглядят древними, и имеют проблемы с отображением интерфейса на современных Win10/11.

1.1. Зачем нужен манифест вFASM-проектах?

Манифест критически важен по нескольким причинам:

• Активация новых визуальных стилей Common Controls v6.0. Без манифеста кнопки, полосы прокрутки и другие элементы управления будут иметь вид из Win2k. Манифест же подключает современную либу comctl32.dll, даруя программе современный внешний вид (тени, прозрачность, округлые края, и т.п).

• Правильное определение версии ОС. Начиная с Win8 функция
Код:
GetVersionEx()
перестала возвращать реальную версию системы, если приложение не имеет совместимого манифеста. Без него программа всегда будет думать, что работает на Win8, даже если запущена на последней Win11.

• Запрос прав админа через UAC (User Account Control). Если коду нужно писать в системные каталоги или реестр, она должна запросить повышение прав. Манифест позволяет указать уровень привилегий:
Код:
asInvoker
= права текущего юзера,
Код:
requireAdministrator
= требовать права админа, или
Код:
highestAvailable
= макс.доступные.

• Профессиональный вид. Встраивание манифеста с описанием программы, версии и другой информацией через ресурс VERSIONINFO, придаёт приложению ухоженный вид.

2. Тип ресурса "RT_MANIFEST"

Для встраивания используется специальный ресурс RT_MANIFEST, константа которого равна 24 (см.инклуд фасма \equates\kernel32.inc). Для стандартного EXE используется ID=1. Существует два способа встроить XML манифеста:

• Внедрение из внешнего файла (рекомендуется для больших XML)
• Встраивание XML прямо в код (удобно для коротких манифестов)

2.1. Подключение внешнегоXML-файла

Это самый чистый и поддерживаемый метод. Вы сохраняете манифест в отдельный файл (например, app.manifest), а затем в fasm указываете путь к этому файлу с помощью директивы
Код:
file
. Вот структура файла app.manifest (минимальный пример):

XML:


Код:

Код для подключения этого файла:

C-подобный:


Код:
section
'.rsrc'
resource data readable
;
// Определяем каталог для манифестов
directory RT_MANIFEST
,
manifests
;
// Определяем сам ресурс: ID=1, язык нейтральный, данные из блока 'resmanifest'
resource manifests
,
1
,
LANG_NEUTRAL
,
resmanifest
;
// Подключаем внешний файл!
resdata resmanifest
        file
'app.manifest'
endres
2.2. ВстраиваниеXMLнепосредственно в код

Данный метод удобен, когда манифест короткий (например только для UAC, или только для визуальных стилей). XML просто вставляется как строка байт с помощью db. Пример для запроса прав админа (requireAdministrator) будет выглядеть так:

C-подобный:


Код:
section
'.rsrc'
resource data readable

    directory  RT_MANIFEST
,
manifests
    resource   manifests
,
1
,
LANG_NEUTRAL
,
resmanifest
;
// XML-строка прямо в коде
resdata resmanifest
        db
''
db
''
db
'  '
db
'  '
db
'    '
db
'      '
db
'        '
db
'      '
db
'    '
db
'  '
db
''
endres
После сборки и запуска программы с таким манифестом, Win будет показывать диалог UAC, запрашивая разрешение на выполнение с правами админа. Определить, что манифест исправно подключён к программе можно по наличию "щита" на иконке исполняемого файла, как это показано ниже (слева xml, справа exe).



2.3. Альтернативный метод

Хотя встраивание манифеста в ресурсы является предпочтительным и надёжным способом, существует ещё вариант. Если вы поместите файл с именем MySoft.exe.manifest в ту же папку, что и MySoft.exe, системный загрузчик образов подхватит его на автомате. Этот метод удобен на этапе отладки, но для финальной сборки использовать его не рекомендуется по сл.причинам:

• При копировании программы можно забыть скопировать манифест.
• Внешние файлы могут быть изменены/удалены антивирусами или юзером.
• Это выглядит непрофессионально.

3. Добавление ресурса VERSIONINFO

Хотя манифест - это важнейший ресурс, профессиональное приложение должно содержать и блок VERSIONINFO. Именно эти данные отображаются в свойствах файла, когда мы кликаем по нему правой кнопкой мыши. В fasm для его создания используется спец.структура, и директива
Код:
versioninfo
.

C-подобный:


Код:
section
'.rsrc'
resource data readable
;
// Определяем каталоги: RT_VERSION и RT_MANIFEST
directory  RT_VERSION
,
versions
,
\
               RT_MANIFEST
,
manifests
;
// Описываем ресурс версии: ID=1, язык нейтральный, данные из блока 'version'
resource versions
,
1
,
LANG_NEUTRAL
,
version
;
// Блок VERSIONINFO
versioninfo version
,
VOS__WINDOWS32
,
VFT_APP
,
VFT2_UNKNOWN
,
LANG_ENGLISH
+
SUBLANG_DEFAULT
,
0
,
\
'FileDescription'
,
'Краткое описание приложения'
,
\
'LegalCopyright'
,
'(C)2024, античат '
,
\
'FileVersion'
,
'1.1.0.0'
,
\
'ProductVersion'
,
'1.0.0.0'
,
\
'OriginalFilename'
,
'MyApp.exe'
;
// Описываем ресурс манифеста
resource manifests
,
1
,
LANG_NEUTRAL
,
resmanifest
    
    resdata resmanifest
        file
'app.manifest'
endres
Обратите внимание, что оба ресурса и манифест и версия имеют одинаковый идентификатор
Код:
ID=1
. Это принципиально важно, т.к. при других значениях загрузчик посчитает блок невалидным и проигнорирует его. Но как могут быть одинаковые ID у двух ресурсов, ведь по логике вещей это не допустимо?

Короткий ответ:
Код:
ID=1
в разных типах ресурсов
Код:
RT_MANIFEST
и
Код:
RT_VERSION
- это разные пространства имён. Они не конфликтуют, потому что идентифицируются не только по ID, а именно парой
Код:
Type + ID
. В секции .rsrc ресурсы организованы в трёхуровневую иерархию:

Код:
1. Type: RT_VERSION(16), RT_MANIFEST(24), RT_DIALOG(5) и т.д.
Код:
2. Name/ID: Уникальный идентификатор внутри этого типа.
Код:
3. Language: LANG_ENGLISH, LANG_NEUTRAL и т.д.
Обычно код создаёт в секции .rsrc три разные ветки:

Код:
• Ветка RT_DIALOG -> ID 37 -> Lang
Код:
• Ветка RT_MANIFEST -> ID 01 -> Lang
Код:
• Ветка RT_VERSION -> ID 01 -> Lang
Для загрузчика образов
Код:
RT_MANIFEST#1
и
Код:
RT_VERSION#1
- это совершенно разные объекты, как файлы C:\Windows\System32\kernel32.dll и D:\MyProject\kernel32.dll. Путь к ним разный, поэтому они живут мирно. Так почему-же версия не отображается, если ID не 1?

Секрет в том, как система ищет инфу о версии. Когда в свойствах файла мы выбираем "Подробно", под катом вызывается
Код:
GetFileVersionInfo()
с таким алго: -"Найти в секции ресурсов тип RT_VERSION(16) с идентификатором VS_VERSION_INFO(1)". Если мы ставим ID=1, Win находит ресурс и версия отображается. Если-же задать ID=2 (42, 1000), api ищет ID=1, не находит его и молча решает «Версии нет». Никакой ошибки не будет, просто поля версии в свойствах файла останутся пустыми.

А почему-же манифест работает с ID=1?
Здесь похожая, но не такая строгая история. Win подхватывает манифест в нескольких случаях:

1. Встроенный, ищется по хард
Код:
ID=1
.
2. Внешний (appname.exe.manifest). Если встроенного
Код:
ID=1
нет, загрузчик ищет манифест рядом с EXE.
3. Динамическая загрузка через
Код:
FindResource() + LoadResource()
. Если мы врукопашную ищем манифест, то сработает любой ID, однако при старте процесса загрузчик этого не делает.

Вот сводная таблица разных вариантов:

Код:
Ресурс      Тип ID Как работает
Код:
----------- --- -- -------------
Код:
RT_MANIFEST 24 1 Загрузчик ищет строго ID=1 для встроенного манифеста.
Код:
RT_VERSION 16 1 GetFileVersionInfo() ищет строго ID=1.
Код:
RT_DIALOG 05 37 DialogBoxParam() использует ID=37, хотя будет работать и при ID=1.
4. Реализация на практике

Ниже представлен код программы, которая запрашивает желаемую привилегию (как у текущего юзера, админ, или макс.возможную), и на основании выбора генерит готовый файл-манифеста, который можно будет подключить к своей программе. Помимо того, что код создаёт внешний XML-файл, он и сам в своей тушке имеет оба ресурса - и
Код:
RT_VERSION
и
Код:
RT_MANIFEST
для отображения визуальных стилей Win10/11.

Как результат получим такое окно. Чтобы обозначить разницу, здесь я сделал 2 скрина - слева с манифестом, а справа без. Как видим стиль кнопок приобрёл уже другой вид: с голубой подсветкой, края округлённые, а если в окне были-бы и другие элементы управления (полосы прокрутки, списки комбо/лист-бокс, и прочее), то изменились-бы и они на более современные. В общем профит от манифестов на лицо.

Просмотреть содержимое манифеста (и даже подправить пару строк) можно в крутой тулзе "CFF-Explorer" как показано на скрине ниже. Ну и конечно специально заточенная для этих нужд утилита "Resource Hacker" позволяет создавать манифесты из своих шаблонов - вписываем в строку "Name" имя своей прожки, и всё пучком. Одним словом, здесь есть из чего выбирать:



А по коду, после того-как получили дескриптор открытого файла (здесь я использовал функцию _lopen(), которая под катом вызывает CreateFile() с дефолтными настройками безопасности), можно в любой момент сбрасывать в него фрагменты данных, и они будут дописываться в конец по текущему указателю. Этот указатель хранится в файловом объекте ядра, и при каждой записи увеличивается на указанное при вызове
Код:
_lwrite()
кол-во байт. Он будет всегда смотреть в конец файла, пока мы не закроем дескриптор по
Код:
CloseHandle()
. Вот внутренняя структура любого файла в отладчике WinDbg, где по смещению(0x68) лежит позиция указателя в файле:

Код:


Код:
0: kd> dt _file_object
nt!_FILE_OBJECT
   +0x000 Type                 : Int2B
   +0x002 Size                 : Int2B
   +0x008 DeviceObject         : Ptr64 _DEVICE_OBJECT
   +0x010 Vpb                  : Ptr64 _VPB   Атрибуты доступа
   +0x04e SharedWrite          : UChar     |
   +0x04f SharedDelete         : UChar     |
   +0x050 Flags                : Uint4B ---+
   +0x058 FileName             : _UNICODE_STRING
   +0x068 CurrentByteOffset    : _LARGE_INTEGER
5. Заключение

Манифесты в FASM это не магия и не проблема. Освоив технику вы перестаёте быть "тем парнем, который пишет ассм под DOS", и становитесь проф.разработчиком под Windows, способным создавать современные приложения с правильным поведением и внешним видом. Используйте директиву
Код:
resdata
для встраивания XML, не забывайте про
Код:
RT_MANIFEST
и
Код:
ID=1
, добавляйте
Код:
VERSIONINFO
для информации о файле, и ваши программы будут выглядеть так, как будто они написаны на самом современном компиляторе. В мире FASM нет границ: если вы можете описать это в коде - ассемблер это соберёт.

Ссылки по теме

MSDN - Описание всех элементов манифеста:
Манифесты приложения - Win32 apps

MSDN - Включение визуальных стилей:
Включение визуальных стилей - Win32 apps

Зачем приложению манифест:
Зачем Win32-приложению манифест?
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.