Что такое код allocselector

Содержание

Знаете ли вы селекторы?

CSS3-селекторы – фундаментально полезная вещь.

Даже если вы почему-то (старый IE?) не пользуетесь ими в CSS, есть много фреймворков для их кросс-браузерного использования CSS3 из JavaScript.

Поэтому эти селекторы необходимо знать.

Основные виды селекторов

Основных видов селекторов всего несколько:

  • * – любые элементы.
  • div – элементы с таким тегом.
  • #id – элемент с данным id .
  • .class – элементы с таким классом.
  • [name=»value»] – селекторы на атрибут (см. далее).
  • :visited – «псевдоклассы», остальные разные условия на элемент (см. далее).

Селекторы можно комбинировать, записывая последовательно, без пробела:

  • .c1.c2 – элементы одновременно с двумя классами c1 и c2
  • a#id.c1.c2:visited – элемент a с данным id , классами c1 и c2 , и псевдоклассом visited

Отношения

В CSS3 предусмотрено четыре вида отношений между элементами.

Самые известные вы наверняка знаете:

  • div p – элементы p , являющиеся потомками div .
  • div > p – только непосредственные потомки

Есть и два более редких:

p – правые соседи: все p на том же уровне вложенности, которые идут после div .

  • div + p – первый правый сосед: p на том же уровне вложенности, который идёт сразу после div (если есть).
  • Функции Win32 API [ A ]

    Delphi , Синтаксис , Справочник по API-функциям

    Откpывает и позициониpует файл pесуpсов на начало pесуpса. После чтения pесуpса файл должен быть закpыт.

    • Instance: Модуль экземляpа, исполнимый файл котоpого содеpжит pесуpс.
    • ResInfo: Нужный pесуpс, созданный путем вызова функции FindResource.

    Описатель файла DOS; -1, если pесуpс не найден.

    Добавляет Str в таблицу атомов. Для каждого уникального стpокового экземпляpа ведется счетчик ссылок.

    • Str: Символьная стpока, заканчивающаяся пустым символом.

    В случае успешного завеpшения — уникальный идентификатоp атома; в пpотивном случае, -1.

    функция находится в файле kernel32.dll

    Добавляет к таблице системных шpифтов pесуpс шpифта из файла pесуpса шpифтов с именем FileName.

    • FileName: Описатель загpуженного модуля или стpока, заканчивающаяся пустым символом.

    Количество добавленных шpифтов; нуль, если шpифты не добавлялись.

    функция находится в файле gdi32.dll

    Вычисляет тpебуемый pазмеp оконного пpямоугольника на основании pазмеpа Rect. Пpедполагается одностpочное меню.

    • Rect: TRect, содеpжащий пpеобpазуемые кооpдинаты пpямоугольника пользователя.
    • Style: Стили окна, пpямоугольник пользователя котоpого пpеобpазуется.
    • Menu: Не нуль, если окно имеет меню.

    функция находится в файле user32.dll

    Вычисляет тpебуемый pазмеp оконного пpямоугольника с pасшиpенным стилем на основании pазмеpа Rect. Пpедполагается одностpочное меню.

    • Rect: TRect, содеpжащий пpеобpазуемые кооpдинаты пpямоугольника пользователя.
    • Style: Стили окна, пpямоугольник пользователя котоpого пpеобpазуется.
    • Menu: Не нуль, если окно имеет меню.
    • ExStyle: Расшиpенный стиль создаваемого окна.

    функция находится в файле user32.dll

    Отобpажает Selector в селектоp сегмента кода.

    • Selector: Селектоp сегмента данных.

    В случае успешного завеpшения — соответствующий селектоp сегмента кода; в пpотивном случае, нуль.

    Выделяет неинициализиpованную память для ResInfo.

    • Instance: Модуль экземляpа, исполнимый файл котоpого содеpжит pесуpс.
    • ResInfo: Нужный pесуpс.
    • Size: Размеp в байтах, выделяемый для pесуpса; игноpиpуется, если нуль.

    Выделенный глобальный блок памяти.

    Распpеделяет новый селектоp, котоpый является точной копией Selector. Если Selector имеет значение nil, то выделяет память под новый, неинициализиpованный селектоp.

    • Selector: Копиpуемый селектоp.

    В случае успешного завеpшения — селектоp; в пpотивном случае, нуль.

    • hdc: Дескриптор контекста устройства.
    • x: Координата x центра круга.
    • y: Координата y центра круга.
    • dwRadius: Радиус круга.
    • eStartAngle: Угол для идентификации отправной точки дуги.
    • eSweepAngle: Угол для идентификации конечной точки дуги

    В случае успешного завеpшения — true; в пpотивном случае, false.

    Заменяет элементы в Palette между StartIndex и NumEntries на PaletteColors.

    • Palette: Логическая палитpа.
    • StartIndex: Пеpвый элемент в оживляемой палитpе.
    • NumEntries: Число элементов в оживляемой палитpе.
    • PaletteColors: Массив стpуктуp TPaletteEntry.

    функция находится в файле gdi32.dll

    Использует дpайвеp языка для пpеобpазования Str в нижний pегистp.

    • Str: Стpока, заканчивающаяся пустым символом, или одиночный символ (в младшем байте).

    Пpеобpазованная стpока или символ.

    функция находится в файле user32.dll

    Использует дpайвеp языка для пpеобpазования Str в нижний pегистp.

    • Str: Буфеp символов.
    • Length: Длина символов в буфеpе; если нуль, то длина составляет 64К (65 536 байт).

    Длина пpеобpазованной стpоки.

    функция находится в файле user32.dll

    Используется для итеpации по стpокам, символы котоpых имеют длину два или более байт.

    • CurrentChar: Стpока, заканчивающаяся пустым символом.

    Указатель на следующий символ в стpоке.

    функция находится в файле user32.dll

    Используется для итеpации в обpатном напpавлении по стpокам, символы котоpых имеют длину два или более байт.

    • Start: Начало стpоки (заканчивающейся пустым символом).
    • CurrentChar: Стpока, заканчивающаяся пустым символом.

    Указатель на пpедыдущий символ в стpоке.

    функция находится в файле user32.dll

    Тpанслиpует AnsiStr в символьный набоp, опpеделенный OEM. Длина может быть больше 64К.

    • AnsiStr: Cтpока (заканчивающаяся пустым символом) символов ANSI.
    • OEMStr: Место, куда копиpуется отpанслиpованная стpока, может совпадать с AnsiStr.

    функция находится в файле user32.dll

    Тpанслиpует AnsiStr в символьный набоp, опpеделенный OEM.

    • AnsiStr: Буфеp символов ANSI.
    • OEMStr: Место, куда копиpуется отpанслиpованная стpока, может совпадать с AnsiStr.
    • Length: Размеp AnsiStr; если нуль, длина pавна 64К.

    функция находится в файле user32.dll

    Использует дpайвеp языка для пpеобpазования Str в веpхний pегистp.

    • Str: Стpока, заканчивающаяся пустым символом или один символ (в младшем байте).

    Пpеобpазованная стpока или символ.

    функция находится в файле user32.dll

    Использует дpайвеp языка для пpеобpазования Str в веpхний pегистp.

    • Str: Буфеp символов.
    • Length: Размеp Str; если нуль, то длина pавна 64К.

    Длина пpеобpазованной стpоки.

    функция находится в файле user32.dll

    Опpеделяет, существует ли на экpане всплывающее окно.

    Не нуль, если всплывающее окно существует; нуль — если нет.

    функция находится в файле user32.dll

    Пpисоединяет в конец меню новый элемент, состояние котоpого опpеделяется Flags.

    • Menu: Изменяемое меню.
    • Flags: Одна или комбинация следующих констант MF: mf_Bitmap, mf_Checked, mf_Disabled, mf_Enabled, mf_Grayed, mf_MenuBarBreak mf_MenuBreak, mf_OwnerDraw, mf_Popup, mf_Separator,
    • mf_String, mf_UnChecked.
    • IDNewItem: Идентификатоp команды или описатель меню в случае всплывающего меню.

    Не нуль в случае успешного завеpшения; нуль — в пpотивном случае.

    функция находится в файле user32.dll

    Рисует эллиптическую дугу, центpиpованную в огpаничивающем пpямоугольнике.

    • DC: Контекст устpойства.
    • X1, Y1: Веpхний левый угол огpаничивающего пpямоугольника.
    • X2, Y2: Пpавый нижний угол огpаничивающего пpямоугольника.
    • X3, Y3: Начальная точка дуги.
    • X4, Y4: Конечная точка дуги.

    Не нуль, если дуга наpисована; нуль — в пpотивном случае.

    Пpимечание: Огpаничивающий пpямоугольник должен быть не длиннее или не шиpе 32 767 единиц.

    функция находится в файле gdi32.dll

    Располагает пиктогpаммы в окне пользователя MDI или пиктогpаммы в окне pабочей области.

    • Wnd: Идентификатоp pодительского окна.

    Высота одной стpоки пиктогpамм; нуль, если пиктогpамм нет.

    функция находится в файле user32.dll

    Статья Функции Win32 API [ A ] раздела Синтаксис Справочник по API-функциям может быть полезна для разработчиков на Delphi и FreePascal.

    Комментарии и вопросы

    Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.

    Получение кода устройства, работающего на Andro >

    Для полноценной работы программного обеспечения необходимо получить лицензию. Для получения лицензии нужно прислать на почту sales@cleverence.ru уникальный код устройства (Ид устройства).

    Уникальный код устройства (Ид устройства) нужно знать только для ТСД, планшетов, смартфонов и микрокиосков.

    Для мобильных принтеров и касс не нужно получать коды устройств, потому что лицензии привязываются не к кассе или мобильному принтеру, а к ТСД (смартфону, пларшету, киоску).

    Получение кодов для другого вида оборудования смотрите в статье «Получение кода устройства».

    Первый способ

    1. Запустите клиента на ТСД.
    2. Откройте выпадающее меню и выберите пункт «О приложении».

    В открывшемся окне с информацией будет доступен код устройства (Ид устройства) в виде строки букв и цифр. Этот код не привязан к ПК, на котором выполнялась установка и не меняется при переустановках программного обеспечения.

    Функция AllocSelector

    Описание:

    function AllocSelector(Selector: Word): Word;

    Распpеделяет новый селектоp, котоpый является точной копией Selector. Если Selector имеет значение nil, то выделяет память под новый, неинициализиpованный селектоp.

    Параметры:

    Selector: Копиpуемый селектоp.

    Возвpащаемое значение:

    В случае успешного завеpшения — селектоp; в пpотивном случае, нуль.

    Описание:

    procedure AnimatePalette(Palette: HPalette; StartIndex: Word; NumEntries: Word; var PaletteColors);

    Заменяет элементы в Palette между StartIndex и NumEntries на PaletteColors.

    Параметры:

    Palette: Логическая палитpа.
    StartIndex: Пеpвый элемент в оживляемой палитpе.
    NumEntries: Число элементов в оживляемой палитpе.
    PaletteColors: Массив стpуктуp TPaletteEntry.

    Keeloq и Двойной динамический код vs Кодграббер

    Если любознательный автолюбитель задает вопрос о том, смогут ли перехватить код брелка его сигнализации и, таким образом, — угнать авто, он получает от установщика автосигнализации чаще всего такой ответ: «Код динамический (иногда добавят название алгоритма шифрования), при каждой новой посылке меняется». Обычно после этого ответа не возникает вопросов и радостный автовладелец уезжает восвояси, спокойный и довольный. Конечно не может быть и речи о спокойствии только на основании того, что автосигнализация поставлена и код у нее динамический. И речь здесь идет не о криптостойкости! — дело в том, что недостаточно одной сигнализации, — это вам скажет любой установщик.

    Все специалисты и работники сервисов сходятся во мнении по следующим вопросам:
    1. Желательно в дополнение к автосигнализации использовать иммобилайзер или реле, управляемое по штатной проводке, что в принципе, на данном этапе развития отрасли — одно и тоже.
    2. Почти необходим замок капота (механический или электромеханический)
    3. Степень угонустойчивости чуть ли не на половину зависит от подхода к установке и профессионализма мастера. С этим трудно не согласиться!

    Однако если взять вполне «приличный» и дорогой охранный комплекс, состоящий из автосигнализации, удаленного реле, висящего на штатном проводе и управляемого от сигнализации, а также, например электромеханического замка на капот Defentime (управляемого от автосигнализации), то электронный ключ от автосигнализации — это все что нужно угонщику, что бы сесть в ваш автомобиль и уехать. Как печально! Вывод напрашивается сам собой, — трудно переоценить значание криптостойкости вашей автосигнализации .

    Окунемся немного в историю и посмотрим, — какже появились на свет все эти Килоги, и прочие алгоритмы шифрования

    В устаревших сигнализациях применялись коды с числом комбинаций до 512, Подбор такого кода занимает менее 1 минуты. Количество комбинаций кодов в современных сигнализациях может достигать нескольких тысяч миллиардов. Первая структура динамического кода была предложена итальянской компанией Autotechnica еще в 1995 году. Но подлинная революция в применении этой технологии произошла, когда компания Microchip изготовила наборы кодирующих и декодирующих устройств, сопроводив их своими руководствами по внедрению. Эта «техническая интервенция» способствовала появлению у разных изготовителей своих собственных оригинальных алгоритмов. Однако, до сих пор продукция фирмы Microrochip пользуется большим спросом, а технология «Keeloq» известна всем, кто не остановил свое знакомство с автомобилем на замке зажигания, двери и «балоннике».

    Именно здесь, я сделаю отступление и расскажу автолюбителям о таком понятии, как антисканирование, — практически стандартная опция для современной автосигнализации. Под этим термином понимают то, что злоумышленник не сможет снять сигнализацию с охраны с помощью сканера. Сканер – это относительно несложное устройство, которое последовательно воспроизводит коды в формате взламываемой сигнализации. Систему с антисканированием нельзя выключить перебором кодов брелока, так как при приеме неверного кода она, на некоторое время блокируется, увеличивая время, необходимое для сканирования. Блокировка снимается многократной передачей правильного кода. При достаточно большом числе возможных кодов перебор займет нереально много времени. Технология антисканирования применяется уже несколько лет и не является новинкой. Системы с антисканированием не защищены от перехвата кодов из эфира с помощью специальных устройств (грабберов или перехватчиков кодов). Антисканирующая пауза является необходимым атрибутом и в системах с динамическим кодом.

    Что же такое динамический код.

    Технология плавающих кодов делает невозможным, как перехват кодов из эфира, так и их подбор. Действительный код шифруется таким образом, что при каждой передаче излучается внешне совершенно другая кодовая посылка. В приемнике действительный код восстанавливается путем математической обработки. Перехват кодов становится бессмысленным, так как невозможно предсказать какая следующая кодовая комбинация снимет сигнализацию с охраны. Простое повторение предыдущей посылки не приведет к выключению сигнализации, так как бывшие в прошлом посылки считаются недействительными. Предсказать же будущую посылку теоретически можно, только зная алгоритм шифрования кода, который держится фирмой-изготовителем в секрете и достаточное количество выборок кода для анализа. Кодовые комбинации повторяются с очень большим интервалом. Исследования модели MICROCAR 052.1 показали, что для данной модели этот период составляет более 65000 нажатий. Можно сказать что, в процессе эксплуатации, передаваемые кодовые комбинации не разу не повторяются – машина не служит 20 лет. Коды-идентификаторы брелоков автосигнализаций с плавающими кодами записываются в заводских условиях и являются уникальными не подлежащими замене в процессе эксплуатации. Технология плавающих кодов очень эффективно защищает сигнализацию от взлома с помощью электронных средств. Степень защиты от расшифровки зависит от применяемого алгоритма кодирования. Именно здесь и кроется одно большое «НО» (см. далее «Двойной динамический код»)

    Рассмотрим немного подробнее, что же представляет из себя динамический код на основе все того же Keeloq

    В основе технологии keeloq лежит понятие секретных кодирующих/декодирующих ключей (шифров), которые преобразуют исходную информацию в кодированную и кодированные данные в исходные.

    Однако к кодирующему ключу разработчикам пришлось добавить еще несколько структур данных специального назначения. Кратко рассмотрим их.

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

    Счетчик синхронизации 16-битовая комбинация счетчика, передаваемая каждый раз при активации кодирующего устройства (кодера), например, путем нажатия кнопки брелока. Счетчик синхронизации формируется в кодере и передается в закодированном виде в составе переменной части посылки. Эта структура позволяет отслеживать синхронность шагов декодирующего и кодирующего устройств. Текущее значение счетчика синхронизации от каждого кодера запоминается в декодере и позволяет отличить принятую следующую посылку от предыдущей или внеочередной, созданной не в соответствии с алгоритмом.

    Дискриминатор 12-битовая произвольная комбинация, передаваемая кодером в закодированном виде в составе переменной части посылки. Он используется для проверки целостности процесса декодирования.

    Серийный номер уникальный номер каждого кодера (брелока-передатчика) из 28 или 32 бит. Формируется при изготовлении кодера и передается в некодированном виде в постоянной части посылки.

    Каждый кодер характеризуется набором из четырех величин, описанных выше: кодирующего ключа, счетчика синхронизации, дискриминатора и серийного номера. Поскольку значения всех этих величин различны для разных кодеров, то декодер должен хранить в памяти столько наборов, сколько кодеров использует система (обычно не более 6 8).

    Формирование кодирующего ключа в кодере производится специальным программатором в процессе изготовления кодера. Для генерации кодирующего ключа необходимы серийный номер и ключ изготовителя.

    Ключ изготовителя 64-битовая комбинация, используемая для образования кодирующего ключа и обеспечивающая разделения всего кодового пространства посылок между разными изготовителями. Ключ изготовителя также записывается в память декодирующего устройства. Естественно, для работы со всеми кодерами системы, произведенными одним изготовителем, достаточно запоминания одного ключа изготовителя.

    Для того, чтобы сигнализация могла опознать «свои» брелки, в кодовой посылке брелка и памяти декодера сигнализации содержатся одинаковые коды-идентификаторы, которые запоминаются сигнализацией при программировании («обучении») брелков. Код — идентификатор каждого брелка уникален и, чаще всего, записывается в кодер брелка при изготовлении.

    Для того, чтобы код-идентификатор нельзя было перехватить из эфира, все (точнее практически все) уже передававшиеся коды нужно отсеивать, как недействительные. Кроме того, код-идентификатор и служебную информацию нельзя передавать в явном виде. Это возможно сделать, если до передачи налагать на код различные неповторяющиеся маски. Чтобы иметь возможность удалить маску при приеме, ее необходимо пронумеровать. В кодер и декодер включен т.н. счетчик синхронизации. Счетчик синхронизации содержит текущий номер маски. Каждое нажатие кнопки брелка приводит к увеличению состояния счетчика синхронизации брелка и изменению налагаемой маски. Типичная емкость счетчика синхронизации — 16 двоичных разрядов. Таким образом, брелок генерирует 65000 неповторяющихся масок.

    Кодовый брелок сигнализации – это миниатюрный передатчик, работающий в диапазоне дециметровых волн (200. 450 МГц). Реже встречаются модели, работающие на инфракрасных лучах, они отличаются малым радиусом действия.
    Для сигнализаций оснащенных брелоками на ИК – лучах перехват кодов весьма затруднен из-за малого радиуса действия и направленности брелоков-передатчиков (при пользовании их приходится направлять в определенное место салона автомобиля с расстояния не более нескольких метров). Эта особенность может создавать неудобства при пользовании. Сигнализации с ИК-брелоками: BOSH Blocktronic IR-US, BOSH Blocktronic IM-US

    Рабочие частоты передатчиков постоянны и нормированы контрольными органами электросвязи стран в которые эти устройства ввозятся.

    Для передачи кода в эфир используется однотранзисторный генератор, работающий на одной из вышеуказанных частот. В современных сигнализациях, во избежание ухода частоты при изменении температуры и влажности, частота передачи стабилизируется с помощью фильтров на поверхностных акустических волнах. Для воспроизведения кода – идентификатора в брелоках используются специализированные микросхемы – кодеры, а также, запрограммированные соответствующим образом, микроконтроллеры.

    Двойной динамический код

    С тех пор, как код – граббер перестал быть экзотикой и доступен угонщикам, все большое значение уделяется степени секретности кодовой посылки, передаваемой с брелока. Как результат этого процесса все большее число систем выпускается с динамическим кодом. Никто не оспаривает его преимуществ. Однако и он не может считаться панацеей на все случаи. Если алгоритм изменения становится известен, (а он известен, по крайней мере, разработчику), то внедриться в систему остается делом техники. Не даром система кодировки так тщательно засекречивается и скрывается производителями сигнализаций. Для исключения и этой возможности для электронного взлома разработан так называемый D2-код, сущность которого заключается в том, что каждому брелоку, помимо разрядного номера, присвоен еще и свой индивидуальный закон изменения кода. Это индивидуальное правило записывается в декодер один раз при вводе (программировании) брелока, в эфире больше не появляется и радиоперехвату недоступно. Таким образом, даже разработчик системы, обладая всей необходимой информацией о способах кодирования и соответствующей аппаратурой, не сможет расшифровать этот код.

    How to pass simple argument to createSelector? #140

    Comments

    Copy link Quote reply

    mistre83 commented Jun 20, 2020 •

    I’m sorry for this question but i’m very new to reselect, react etc.

    Its possible to pass an argument to createSelector ?

    I have a selector like this:

    getMonitors is a «simple selector» that take a part of the state:

    export const getMonitors = state => state.systems.collection[0].monitors;

    Dont care abut the [0], i’m just testing for semplicity :)

    the getMonitorsOfType should call getMonitors and the return value should be _.get(monitors, inputValue).

    For example, i’ve think an selector like this:

    This inputValue is just a variable that come from my components (is the routing properties: this.props.params.monitor_id).

    So, in mapStateToProps i should have:

    Maybe i’m doing all in a totally wrong way.

    Самый маленький шелл-код. Создаем 44-байтовый Linux x86 bind shellcode

    Содержание статьи

    Shell-код представляет собой набор машинных команд, позволяющий получить доступ к командному интерпретатору (cmd.exe в Windows и shell в Linux, от чего, собственно, и происходит его название). В более широком смысле shell-код — это любой код, который используется как payload (полезная нагрузка для эксплоита) и представляет собой последовательность машинных команд, которую выполняет уязвимое приложение (этим кодом может быть также простая системная команда, вроде chmod 777 /etc/shadow) :

    Немного теории

    Уверен, что многие наши читатели и так знают те истины, которые я хочу описать в теоретическом разделе, но не будем забывать про недавно присоединившихся к нам хакеров и постараемся облегчить их вхождение в наше непростое дело.

    Системные вызовы

    Системные вызовы обеспечивают связь между пространством пользователя (user mode) и пространством ядра (kernel mode) и используются для множества задач, таких, например, как запуск файлов, операции ввода-вывода, чтения и записи файлов.

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

    Регистры

    Регистры — специальные ячейки памяти в процессоре, доступ к которым осуществляется по именам (в отличие от основной памяти). Используются для хранения данных и адресов. Нас будут интересовать регистры общего назначения: EAX, EBX, ECX, EDX, ESI, EDI, EBP и ESP.

    Стеком называется область памяти программы для временного хранения произвольных данных. Важно помнить, что данные из стека извлекаются в обратном порядке (что сохранено последним — извлекается первым). Переполнение стека — достаточно распространенная уязвимость, при которой у атакующего появляется возможность перезаписать адрес возврата функции на адрес, содержащий shell-код.

    Проблема нулевого байта

    Многие функции для работы со строками используют нулевой байт для завершения строки.

    Таким образом, если нулевой байт встретится в shell-коде, то все последующие за ним байты проигнорируются и код не сработает, что нужно учитывать.

    Необходимые нам инструменты

    • Linux Debian x86/x86_64 (хотя мы и будем писать код под x86, сборка на машине x86_64 проблем вызвать не должна);
    • NASM — свободный (LGPL и лицензия BSD) ассемблер для архитектуры Intel x86;
    • LD — компоновщик;
    • objdump — утилита для работы с файлами, которая понадобится нам для извлечения байт-кода из бинарного файла;
    • GCC — компилятор;
    • strace — утилита для трассировки системных вызовов.

    Если бы мы создавали bind shell классическим способом, то для этого нам пришлось бы несколько раз дергать сетевой системный вызов socketcall() :

    • net.h/SYS_SOCKET — чтобы создать структуру сокета;
    • net.h/SYS_BIND — привязать дескриптор сокета к IP и порту;
    • net.h/SYS_LISTEN — начать слушать сеть;
    • net.h/SYS_ACCEPT — начать принимать соединения.

    И в конечном итоге наш shell-код получился бы достаточно большим. В зависимости от реализации в среднем выходит 70 байт, что относительно немного. Но не будем забывать нашу цель — написать максимально компактный shell-код, что мы и сделаем, прибегнув к помощи netcat!

    Почему размер так важен для shell-кода?

    Ты, наверное, слышал, что при эксплуатации уязвимостей на переполнение буфера используется принцип перехвата управления, когда атакующий перезаписывает адрес возврата функции на адрес, где лежит shell-код. Размер shell-кода при этом ограничен и не может превышать определенного значения.

    Shell-код мы будем писать на чистом ассемблере, тестировать — в программе на С. Наша заготовка bind_shell_1.nasm , разбитая для удобства на блоки, выглядит следующим образом:

    Сохраним ее как super_small_bind_shell_1.nasm и далее скомпилируем:

    а затем слинкуем наш код:

    и запустим получившуюся программу через трассировщик (strace), чтобы посмотреть, что она делает:

    Запуск bind shell через трассировщик

    Xakep #246. Учиться, учиться, учиться!

    Как видишь, никакой магии. Через системный вызов execve() запускается netcat , который начинает слушать на порте 12345, открывая удаленный шелл на машине. В нашем случае мы использовали системный вызов execve() для запуска бинарного файла /bin/nc с нужными параметрами ( -le/bin/sh -vp12345 ).

    execve() имеет следующий прототип:

    • filename обычно указывает путь к исполняемому бинарному файлу — /bin/nc ;
    • argv[] служит указателем на массив с аргументами, включая имя исполняемого файла, — [«/bin//nc», «-le//bin//sh», «-vp12345»] ;
    • envp[] указывает на массив, описывающий окружение. В нашем случае это NULL, так как мы не используем его.

    Синтаксис нашего системного вызова (функции) выглядит следующим образом:

    Описываем системные вызовы через ассемблер

    Как было сказано в начале статьи, для указания системного вызова используется соответствующий номер (номера системных вызовов для x86 можно посмотреть здесь: /usr/include/x86_64-linux-gnu/asm/unistd_32.h ), который необходимо поместить в регистр EAX (в нашем случае в регистр EAX, а точнее в его младшую часть AL было занесено значение 11, что соответствует системному вызову execve() ).

    Аргументы функции должны быть помещены в регистры EBX, ECX, EDX:

    • EBX — должен содержать адрес строки с filename — /bin//nc ;
    • ECX — должен содержать адрес строки с argv[] — «/bin//nc» «-le//bin//sh» «-vp12345» ;
    • EDX — должен содержать null-байт для envp[] .

    Регистры ESI и EDI мы использовали как временное хранилище для сохранения аргументов execve() в нужной последовательности в стек, чтобы в блоке 5 (см. код выше) перенести в регистр ECX указатель (указатель указателя, если быть более точным) на массив argv[] .

    Ныряем в код

    Разберем код по блокам.

    Блок 1 говорит сам за себя и предназначен для определения секции, содержащей исполняемый код и указание линкеру точки входа в программу.

    Блок 2

    Обнуляем регистр EDX, значение которого (NULL) будет использоваться для envp[] , а также как символ конца строки для вносимых в стек строк. Обнуляем регистр через XOR, так как инструкция mov edx, 0 привела бы к появлению null-байтов в shell-коде, что недопустимо.

    Важно!

    Аргументы для execve() мы отправляем в стек, предварительно перевернув их справа налево, так как стек растет от старших адресов к младшим, а данные из него извлекаются наоборот — от младших адресов к старшим.

    Для того чтобы перевернуть строку и перевести ее в hex, можно воспользоваться следующей Linux-командой:

    Блок 3

    Ты, наверное, заметил странноватый путь к бинарнику с двойными слешами. Это делается специально, чтобы число вносимых байтов было кратным четырем, что позволит не использовать нулевой байт (Linux игнорирует слеши, так что /bin/nc и /bin//nc — это одно и то же).

    Илон Маск рекомендует:  Что такое код ibase_commit

    Блок 4

    Блок 5

    Почему в AL, а не в EAX? Регистр EAX имеет разрядность 32 бита. К его младшим 16 битам можно обратиться через регистр AX. AX, в свою очередь, можно разделить на две части: младший байт (AL) и старший байт (AH). Отправляя значение в AL, мы избегаем появления нулевых байтов, которые бы автоматически появились при добавлении 11 в EAX.

    Извлекаем shell-код

    Чтобы наконец получить заветный shell-код из файла, воспользуемся следующей командой Linux:

    и получаем на выходе вот такой вот симпатичный shell-код:

    Тестируем

    Для теста будем использовать следующую программу на С:

    Компилируем. NB! Если у тебя x86_64 система, то может понадобиться установка g++-multilib :

    Проверяем bind shell

    Хех, видим, что наш shell-код работает: его размер — 58 байт, netcat открывает шелл на порте 12345.

    Оптимизируем размер

    58 байт — это довольно неплохо, но если посмотреть в shellcode-раздел exploit-db.com, то можно найти и поменьше, например вот этот размером в 56 байт.

    Можно ли сделать наш код существенно компактнее?

    Можно. Убрав блок, описывающий номер порта. При таком раскладе netcat все равно будет исправно слушать сеть и даст нам шелл. Правда, номер порта нам теперь придется найти с помощью nmap . Наш новый код будет выглядеть следующим образом:

    А теперь попробуем подключиться и получить удаленный шелл-доступ. С помощью Nmap узнаем, на каком порте висит наш шелл, после чего успешно подключаемся к нему все тем же netcat :

    И снова проверяем bind shell

    Bingo! Цель достигнута: мы написали один из самых компактных Linux x86 bind shellcode. Как видишь, ничего сложного ;).

    querySelector и querySelectorAll. Полный контроль над страницей. (Страница 1 из 2)

    Форум СисТема iMacros → Обучение → querySelector и querySelectorAll. Полный контроль над страницей.

    Чтобы отправить ответ, вы должны войти или зарегистрироваться

    Сообщений с 1 по 25 из 32

    1 Тема от adminSistem 2020-02-24 22:38:53 — querySelector и querySelectorAll. Полный контроль над страницей.

    • adminSistem
    • Администратор
    • Неактивен
    • Зарегистрирован: 2020-02-24
    • Сообщений: 275
    • Репутация : [ 22 | 0 ]

    После того как вы научились писать самые простые команды из файла iim в файл js вы рано или поздно сталкнетесь с необходимостью работать с кодом страницы браузера. На сайте СисTема в материале для изучения я затронул несколько вариантов взаимодействия. Такие как getElementsByClassName, getElementById и т.д, и вы скорее всего уже столкнулись с тем, как сложно с ними работать. Но есть альтернативный универсальный вариант, который перекроет все потребности. Это querySelector и querySelectorAll. Дочитайте обязательно этот пост до конца, и ваша пленочка порвется, потому что это скорее всего то, чего вам не хватало. Вот простые примеры взаимодействия с названием этого сайта на этой странице:

    Это может показаться довольно непонятным, но все на самом деле просто. content.document.querySelector это доступ к элементу, на который мы попадаем по группе селекторов которые указаны в кавычках. Для того чтоб узнать эту группу, достаточно кликнуть на элементе страницы правой кнопкой мышки, выбрать «Икспектировать элемент с помощью Firebag», и на подсвеченной строке в коде выбрать «Скопировать CSS-путь»(смотрите видео) Вот и все, вся группа селекторов окажется в буфере. Теперь если ее подставить в ковычки querySelector мы можем делать с ним все что угодно. Эксперементировать можно в пробном файле. Желательно только удалить лишние селекторы чтоб строка не была очень длинная.

    Если querySelector возвращает первый элемент на странице который совпадает по селекторам, то querySelectorAll возвращает список всех элементов, и это иногда очень полезно. Они возвращаются в объекте типа NodeList, он имеет свойства, схожие с массивом, но это не массив. Поэтому предлагаю простенькую функцию, которая может сложить в массив все элементы возвращаемого объекта:

    Операционная система Microsoft Windows 3.1 для программиста

    2. Управление памятью

    В этой главе мы рассмотрим механизм управления памятью в операционной системе Windows и функции программного интерфейса Windows, предназначенные для работы с оперативной памятью. Если вы раньше составляли программы только для операционной системы MS-DOS, система управления памятью, реализованная в Windows, может показаться вам очень сложной и запутанной. Однако в отличие от MS-DOS, операционная система Windows является мультизадачной и к тому же использует защищенный режим работы процессора. Все это не может не оказать влияние на сложность системы управления памятью.

    До сих пор в наших приложениях мы почти не использовали функции управления памятью. Там же где это было абсолютно необходимо, мы получали у Windows буфер памяти с помощью хорошо знакомой вам из MS-DOS функции malloc. В некоторых случаях вы можете продолжать использовать эту функцию, однако для приложений Windows предусмотрены и другие, более мощные средства.

    Защищенный режим работы процессора накладывает на приложения свои ограничения. Если программа, составленная для MS-DOS, имеет доступ к любому участку основной, расширенной или дополнительной памяти, а также к любому оборудованию компьютера (через порты ввода/вывода), приложение Windows поставлено в жесткие рамки. Например, приложение может работать только с теми блоками памяти, которые ей принадлежат или получены от операционной системы. Приложение не может выполнять запись в сегмент кода и не может передавать управление в сегмент данных. Что же касается портов ввода/вывода, то в расширенном режиме работы приложение, как правило, не имеет к ним непосредственного доступа. Если приложение попытается вывести данные в порт, это приведет к переключению задачи. Операционная система Windows проверит номер порта и, возможно, предоставит вам возможность что-нибудь в него записать. А возможно, что и не предоставит, выполнив вашу команду ввода/вывода как команду NOP.

    Все указанные выше ограничения необходимы в мультизадачной среде. Если разрешить приложениям обращаться к любым участкам оперативной памяти, недостаточно хорошо отлаженное приложение сможет разрушить операционную систему или другое приложение, работающее параллельно. Если разрешить приложениям работать с портами ввода/вывода, может возникнуть конфликт из-за попытки двух приложений работать одновременно с одним периферийным устройством.

    Однако приложение Windows, тем не менее, может делать все что угодно, если оно работает вместе с так называемым виртуальным драйвером или, как его еще называют, драйвером виртуального устройства ввода/вывода. Виртуальный драйвер — это особая разновидность драйверов в Windows. Виртуальные драйверы предназначены для создания виртуальных устройств ввода/вывода, предоставляемых в пользование параллельно работающим приложениям Windows и виртуальным машинам MS-DOS. Так как виртуальные драйверы работают непосредственно с аппаратурой, для них не действует большинство ограничений, накладываемых на приложения Windows. В частности, виртуальный драйвер может обращаться к любой области памяти, выполнять команды ввода/вывода и привилегированные команды процессора.

    Поэтому, если создаваемое вами приложение должно работать с нестандартной аппаратурой в режиме реального времени, использовать канал прямого доступа к памяти или аппаратные прерывания, вы должны создать собственный виртуальный драйвер и поставлять его вместе с приложением. Для разработки драйверов вам необходимо приобрести Microsoft Driver Development Kit for Windows 3.1, в состав которого, кроме документации и исходных текстов некоторых стандартных драйверов входит специальная версия ассемблера и редактора связей, а также утилиты, необходимые для создания виртуальных драйверов.

    Разработка драйверов для Windows — тема для отдельной книги, которая, возможно, еще будет нами написана. Сейчас мы хотели бы подчеркнуть, что в операционной системе Windows обычные приложения никогда не обращаются напрямую к аппаратуре и не работают с системными областями памяти, такими, как таблицы дескрипторов прерываний или видеопамять. Все это делают драйверы и виртуальные драйверы. Поэтому ограничения, накладываемые на обычные приложения Windows, никак не сказываются на функциональных возможностях самого приложения. Если ваша задача не решается в рамках обычного приложения, создайте свой драйвер и организуйте связь между драйвером и приложением. Если и драйвер не в силах сделать то, что вам нужно (стандартный драйвер, например, не может выполнять привилегированные команды процессора), создайте виртуальный драйвер, которому разрешено все. Пусть ваше приложение занимается выводом данных на экран и обработкой сообщений от клавиатуры и мыши, а драйвер работает с аппаратурой и выполняет «запретные» привилегированные команды процессора.

    В расширенном режиме работы Windows приложения могут пользоваться так называемой виртуальной памятью. Виртуальная память позволяет создать иллюзию работы с оперативной памятью огромного размера — десятки и сотни мегабайт! Реально в физической памяти располагаются только те области виртуальной памяти, к которым чаще всего происходит обращение. Остальные области памяти (страницы памяти) хранятся на диске в специальном файле. Виртуальная память облегчает работу с очень большими массивами данных. Вы можете, например, получить у Windows буфер размером 10 Мбайт и заполнить его содержимым файла, затем выполнить сортировку этого буфера и записать результат в тот же самый или другой файл.

    В документации, поставляющейся вместе с SDK, выделяются семь типов памяти, которые могут использоваться приложениями. Это статическая память, автоматическая память, локальная и глобальная память, память, резервируемая при регистрации класса окна, память, резервируемая при создании самого окна, и память, выделяемая для загрузки ресурсов. Вы должны научиться пользоваться всеми типами памяти, так как каждый из перечисленных выше типов памяти предназначен для решения своего круга задач.

    2.1. Особенности защищенного режима работы процессора

    В томе 6 «Библиотеки системного программиста», который называется «Защищенный режим процессоров Intel 80286/80386/80486», мы подробно рассмотрели работу процессора 80286 в защищенном режиме и особенности адресации памяти процессорами 80386 и 80486. Там же приведены примеры программ, переключающие процессор в защищенный режим работы и выполняющие в этом режиме обращение к аппаратуре компьютера. Однако, учитывая, что в вашем распоряжении может не оказаться указанного выше тома, мы приведем самые необходимые сведения о защищенном режиме в этой главе.

    Адресация памяти в реальном режиме

    Для адресации байта памяти в реальном режиме работы используются две 16-разрядные компоненты адреса — сегмент и смещение. Физический адрес , который попадает на шину адреса системной платы компьютера, складывается (в буквальном смысле этого слова) из сдвинутой влево на четыре бита и дополненной справа четырьмя нулевыми битами сегментной компоненты и компоненты смещения. Перед сложением компонента смещения расширяется до 20 бит так, что в старшие четыре бита записываются нули (рис. 2.1).

    Рис. 2.1. Получение физического адреса в реальном режиме

    Задавая произвольные значения для сегмента и смещения мы можем сконструировать физический адрес для обращения к памяти размером 1 Мбайт плюс 64 Кбайт (и минус 16 байт).

    Адрес, состоящий из сегмента и селектора, мы будем называть логическим адресом реального режима . Диапазон логических адресов от 0000h:0000h до FFFFh:000Fh соответствует диапазону физических адресов от 00000h до FFFFFh. Этот диапазон адресов соответствует первому мегабайту оперативной памяти.

    Диапазон логических адресов от FFFFh:0010h до FFFFh:FFFFh соответствует так называемой области старшей памяти (High Memory Area). Размер области старшей памяти равен 64 Кбайта без 16 байт, и эта память доступна в реальном режиме для процессора модели 80286 и более старших моделей. Если вы работаете с операционной системой MS-DOS версии 5.0 или 6.2, имеет смысл загрузить ядро MS-DOS в область старших адресов, указав в файле config.sys команду:

    Недостатки реального режима работы процессора очевидны. Вы не можете использовать расширенную память, расположенную в адресном пространстве выше области старшей памяти. Если в вашем компьютере установлено 16 Мбайт оперативной памяти, процессор не сможет непосредственно адресовать из них целых 15 Мбайт (рис. 2.2).

    Рис. 2.2. Адресация памяти в MS-DOS

    На заре развития персональных компьютеров оперативная память размером в 1 Мбайт считалась достаточно большой для решения любых мыслимых задач. Однако с появлением Windows и внедрением графического пользовательского интерфейса критерии оценки объема памяти резко изменились. Теперь минимальный объем памяти для нормальной работы приложений Windows составляет 4 Мбайта, а для некоторых приложений (например, для системы разработки Borland C++ for Windows версии 4.0 или Microsoft Visual C++) требуется 8 Мбайт или даже 16 Мбайт. Схема адресации реального режима непригодна для работы с такими большими объемами памяти, так как в этой схеме для физического адреса предусмотрено всего 20 разрядов.

    Вторым крупным недостатком схемы адресации реального режима является то, что программы, работающие в реальном режиме, имеют полный доступ ко всей адресуемой памяти. Несмотря на то, что в MS-DOS имеются функции управления памятью, с помощью которых программы могут получить в свое распоряжение блоки памяти, ничто не помешает программе выполнить запись за пределами полученного блока или даже в системную область памяти, разрушив MS-DOS.

    Если в мультизадачной среде одна задача может писать данные в область памяти, отведенной другой задаче, она может разрушить и эту задачу, и ядро операционной системы. Поэтому в мультизадачных операционных системах, разработанных для процессоров серии Intel 80xxx или Pentium, применяется только защищенный режим работы процессора.

    Адресация памяти в защищенном режиме

    В защищенном режиме, как и в реальном, логический адрес состоит из двух компонент. Однако эти компоненты называются не сегмент и смещение, а селектор и смещение . Для вычисления физического адреса в процессоре 80286 используются также две таблицы дескрипторов — глобальная таблица дескрипторов GDT (Global Descriptor Table ) и локальная таблица дескрипторов LDT (Local Descroptor Table ). Селектор используется для адресации ячейки одной из таблиц дескрипторов, содержащей помимо прочей информации базовый 24-разрядный адрес сегментов. Для получения физического адреса базовый адрес складывается со смещением, расширенным до 24 разрядов (рис. 2.3).

    Рис. 2.3. получение физического адреса в процессоре 80286

    Согласно этой схеме адресации памяти, селектор содержит номер ячейки таблицы дескрипторов, но не компоненту физического адреса. Программа может задавать не любые значения селекторов, а только те, которые соответствуют существующим ячейкам таблицы дескрипторов. Разумеется, программа может загрузить в сегментный регистр любое значение, однако при попытке обратиться к сегменту памяти с использованием неправильного селектора работа программы будет прервана.

    Таким образом, несмотря на то, что компоненты адреса остались, как и в реальном режиме, 16-разрядными, новая схема адресации защищенного режима процессора 80286 позволяет адресовать до 16 Мбайт памяти, так как в результате преобразования получается 24-разрядный физический адрес.

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

    Рис. 2.4. Формат селектора

    Поле TI (Table Indicator ) используется для выбора таблицы дескрипторов. Как мы уже говорили, существуют таблицы дескрипторов двух типов. В любой момент времени может использоваться одна глобальная таблица дескрипторов и одна локальная таблица дескрипторов. Если бит TI равен 0, для выборки базового адреса используется глобальная таблица дескрипторов GDT, если 1 — локальная LDT.

    Зачем нужно использовать дескрипторные таблицы двух типов?

    В мультизадачной операционной системе можно использовать одну глобальную таблицу дескрипторов для описания областей памяти, принадлежащей операционной системе и несколько локальных таблиц дескрипторов для каждой задачи. В этом случае при соответствующей настройке базовых адресов можно изолировать адресные пространства операционной системы и отдельных задач. Если сделать так, что каждая задача будет пользоваться только своей таблицей дескрипторов, любая задача сможет адресоваться только к своим сегментам памяти, описанным в соответствующей таблице, и к сегментам памяти, описанным в глобальной таблице дескрипторов. В системе может существовать только одна глобальная таблица дескрипторов.

    Поле RPL (Requested Privilege Level ) селектора содержит уровень привилегий, запрошенный программой при обращении к сегменту. Программа может обращаться только к таким сегментам, которые имеют соответствующий уровень привилегий. Поэтому программа не может, например, воспользоваться глобальной таблицей дескрипторов для получения доступа к описанным в ней системным сегментам, если она не обладает достаточным уровнем привилегий. На этом основана защита системных данных от разрушения (преднамеренного или в результате программной ошибки) со стороны прикладных программ.

    Таблица дескрипторов содержит, помимо базового адреса сегмента, другую информацию, описывающую сегмент (рис. 2.5). Точный формат дескриптора, а также других структур данных и системных регистров, имеющих отношение к работе в защищенном режиме, вы можете найти в 6 томе «Библиотеки системного программиста».

    Рис. 2.5. Формат дескриптора сегмента процессора 80286

    В частности, дескриптор содержит размер сегмента (предел). При вычислении физического адреса процессор следит за тем, чтобы физический адрес не выходил за пределы, указанные в дескрипторе сегмента. Программа не может обратиться к памяти, лежащей вне пределов, указанных в дескрипторе. Если же она попробует это сделать, ее работа будет прервана. Поэтому, создав, например, сегмент для хранения массива размером 100 байт, вы не сможете записать в него 101 байт или 10 Кбайт данных.

    Поле доступа содержит уровень привилегий сегмента и информацию о типе сегмента. Существуют сегменты кода, сегменты данных и системные сегменты. Кроме того, для сегмента кода можно запретить операцию чтения, а для сегмента данных — операцию записи. Поэтому операционная система может создать сегменты кода, которые можно выполнять, но нельзя читать, и сегменты данных, защищенные от записи.

    Что же касается привилегий, в процессорах 80ххх и Pentium существуют четыре уровня привилегий — от 0 до 3, причем наибольшие привилегии соответствуют уровню 0. Уровни привилегий часто называют также кольцами защиты (рис. 2.6).

    Рис. 2.6. Кольца защиты

    В кольце 0 обычно работает ядро операционной системы. Кольцо 1 соответствует уровню привилегий драйверов, кольцо 2 — системам, таким как системы управления базами данных. В наименее привилегированном кольце 3 располагаются прикладные программы, запускаемые пользователем.

    Описанная выше схема распределения привилегий может изменяться от одной операционной системы к другой. В операционной системе Windows 3.1 в нулевом кольце располагаются только виртуальные драйверы, все остальные модули Windows, а также приложения, работают в кольце 3.

    Процессоры 80386, 80486 и Pentium используют более сложную схему адресации памяти, которая, однако, остается прозрачной для программиста.

    Преобразование адреса в этих процессорах является многоступенчатым. Программы адресуют память с помощью логического адреса, состоящего из 16-разрядного селектора и 32-разрядного смещения. Так же, как и в процессоре 80286, селектор используется для выборки базового адреса сегмента из глобальной или локальной таблицы дескрипторов. Отличие заключается в том, что во-первых, используются 32-разрядные базовый адрес и смещение, а во-вторых, результат сложения называется линейным адресом и используется не для непосредственной адресации памяти, а для дальнейших преобразований (рис. 2.7).

    Рис. 2.7. Преобразование логического адреса в линейный

    Старшие десять бит линейного адреса используются как индекс в каталоге таблиц страниц (рис. 2.8).

    Рис. 2.8. Преобразование линейного адреса в физический

    В каталоге таблиц страниц хранятся дескрипторы, содержащие помимо другой информации, физические адреса таблиц страниц.

    Следующие десять бит линейного адреса используются для выбора из таблицы страниц, адрес которой определяется старшими десятью битами линейного адреса.

    Таблица страниц может описывать до 1024 страниц размером 4096 байт.

    Младшие двенадцать бит линейного адреса содержат смещение адресуемого байта внутри страницы.

    Отметим, что преобразование линейного адреса в физический выполняется процессором с помощью каталога таблиц страниц и таблиц страниц , подготовленных операционной системой. Программист, создающий приложения для Windows, никогда не работает с таблицами страниц или каталогом таблиц страниц. Он пользуется логическим адресом в формате , поэтому схема преобразования логического адреса в физический остается для него прозрачной.

    Операционная система Microsoft Windows версии 3.1 может работать, как вы знаете, в стандартном и расширенном режиме . В первом случае используется схема адресации процессора 80286, даже если в компьютере установлен процессор 80386. Если Windows работает на процессоре 80386, 80486 или Pentium, при наличии достаточного объема оперативной памяти (больше 2 Мбайт) по умолчанию используется расширенный режим работы и, соответственно, схема преобразования адресов процессора 80386.

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

    Описанная выше схема адресации в защищенном режиме накладывает ограничения на операции, которое приложение Windows может выполнять над селекторами.

    Приложение Windows не должно выполнять над селекторами арифметические операции и операции сравнения

    Программируя для реального режима операционной системы MS-DOS, вы, возможно, при адресации блока памяти большого размера (больше 64 Кбайт) изменяли содержимое сегментных регистров. В защищенном режиме вы не можете делать никаких предположений относительно базового адреса следующего или предыдущего дескриптора в локальной или глобальной таблице дескрипторов.

    Сказанное не означает, что приложения Windows не могут работать с блоками памяти, занимающими несколько сегментов. В этом случае для адресации вам нужно использовать специальные методы. Однако, если вы составляете приложение на языке программирования С или С++, при определении указателей на блоки памяти размером больше, чем 64 Кбайт, можно воспользоваться ключевым словом huge. Для таких указателей при необходимости будет автоматически выполняться переключение на нужные селекторы.

    Работа приложения Windows не должна зависеть от уровня привилегий, предоставленного приложению операционной системой, так как в новых версиях Windows этот уровень может измениться.

    Приведем исходный текст приложения SELECTOR, с помощью которого вы сможете проанализировать структуру селектора сегмента кода и сегмента данных, взятых из регистров CS и DS (листинг 2.1).

    Листинг 2.1. Файл selector/selector.cpp

    Это приложение переписывает текущее содержимое регистров процессора CS и DS в переменные uSelCS и uSelDS. Далее содержимое бита TI селекторов, взятых из регистров DS и CS, переписывается в переменные uTICS и uTIDS, соответственно.

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

    Рис. 2.9. Содержимое регистров CS и DS

    Так как содержимое поля TI равно 1, это означает, что для адресации сегмента кода и сегмента данных используется локальная таблица дескрипторов.

    В операционной системе Windows версии 3.1 все приложения используют одну общую локальную таблицу дескрипторов, что в принципе не исключает взаимного влияния приложений. Это означает, что адресные пространства приложений Windows не изолированы друг от друга. Поэтому не пытайтесь загружать в сегментные регистры неправильные селекторы. В следующих версиях Windows каждое приложение будет иметь свое собственное адресное пространство.

    Используйте только те селекторы, которые получены приложением от операционной системы Windows.

    Файл определения модуля приложения SELECTOR ничем не примечателен и приведен в листинге 2.2.

    Листинг 2.2. Файл selector/selector.def

    Обработка прерываний в защищенном режиме

    В реальном режиме для обработки прерываний используется таблица векторов прерываний, расположенная в первом килобайте адресного пространства. Эта таблица состоит из 256 элементов размером 4 байта, которые содержат полный адрес обработчиков прерывания в формате .

    Как вы знаете, существуют аппаратные и программные прерывания. Аппаратные прерывания вырабатываются периферийными устройствами, как правило, при завершении ими операции ввода/вывода. Эти прерывания являются асинхронными по отношению к запущенным программам. Программные прерывания вызываются командой INT. Программные прерывания являются синхронными, так как они инициируются самой программой.

    В ответ на прерывание любого типа в реальном режиме в регистры CS:IP процессора загружается адрес, взятый из соответствующей ячейки таблицы векторов прерываний, после чего управление передается по этому адресу. Обработчик прерываний, выполнив все необходимые действия, возвращает управление прерванной программе, выполняя команду IRET.

    Программы MS-DOS широко используют программные прерывания для получения обслуживания от MS-DOS и BIOS.

    Механизм обработки прерываний в защищенном режиме намного сложнее. Для определения адресов обработчиков прерываний в защищенном режиме используется дескрипторная таблица прерываний IDT (Interrupt Descriptor Table ), расположение которой определяется содержимым специального системного регистра. Эта таблица содержит дескрипторы специальных типов — вентили прерываний, вентили исключений и вентили задач.

    Вентиль прерываний содержат не только логический адрес обработчика прерывания, но и поле доступа. Программа может вызвать прерывание только в том случае, если она имеет для этого достаточный уровень доступа. Таким образом, операционная система, работающая в защищенном режиме, может запретить прикладным программам вызывать некоторые или все программные прерывания.

    Обычные приложения Windows никогда не должны вызывать программные прерывания, так как для взаимодействия с операционной системой используется другой механизм, основанный на вызове функций из библиотек динамической загрузки. Тем не менее, некоторые прерывания (например, INT 21h) все же можно использовать. Для таких прерываний Windows выполняет трансляцию адресов из формата защищенного режима в формат реального режима.

    Приложение Windows не должно пытаться изменить дескрипторную таблицу прерываний. Не следует также думать, что эта таблица расположена по адресу 0000h:0000h, селектор 0000h вообще не используется для адресации памяти.

    Если в этом нет особой необходимости, приложение Windows не должно вызывать программные прерывания. Для работы с файлами, принтером, для вывода на экран следует вызывать функции программного интерфейса операционной системы Windows.

    2.2. Память в различных режимах работы Windows

    В зависимости от режима работы (стандартный или расширенный) операционная система Windows использует то или иное распределение памяти. В любом случае процессор работает в защищенном режиме.

    Операционная система Windows версии 3.0 могла работать и в реальном режиме (для чего ее надо было запускать с параметром /r), однако версия 3.1 этот режим больше не поддерживает.

    Сетевой вариант операционной системы Windows — Windows for Workgroups версии 3.11 работает только в расширенном режиме.

    Стандартный режим работы

    Для работы Windows версии 3.1 в стандартном режиме в компьютере должен быть установлен процессор 80286 или 80386, а также не менее 1-2 Мбайт оперативной памяти.

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

    В пределах первых 640 Кбайт стандартной памяти находится операционная система MS-DOS, драйверы и резидентные программы, запущенные до загрузки Windows.

    В стандартном режиме Windows версии 3.1 не может адресовать более 16 Мбайт памяти. Такое ограничение накладывается схемой адресации процессора 80286. Даже если вы запустили Windows в стандартном режиме на процессоре 80386, указанное ограничение продолжает действовать, так как в этом случае процессор 80386 будет работать с памятью как его предшественник, процессор 80286.

    Расширенный режим работы

    Расширенный режим работы Windows доступен в том случае, если в компьютере установлен процессор 80386, 80486, Pentium, и имеется по крайней мере 2 Мбайт расширенной оперативной памяти.

    В расширенном режиме включается механизм виртуальной памяти, позволяющий теоретически адресовать до 512 Мбайт памяти. При этом в Windows версии 3.1 можно использовать до 256 Мбайт физической оперативной памяти и создать файл виртуальной памяти размером до 256 Мбайт.

    Схема адресации памяти процессора 80386 накладывает ограничение на количество дескрипторов в глобальной и локальной таблице дескрипторов — можно создать не более 8192 дескрипторов в каждой из таблиц. Так как все приложения Windows версии 3.1 используют одну общую локальную таблицу дескрипторов, всего для приложений Windows можно создать не более 8192 дескриптора, описывающих сегменты размером до 64 Кбайт. Однако реально создаются сегменты меньшего размера, поэтому Windows не позволяет приложениям использовать все 512 Мбайт памяти.

    Сегодня такие требования к объему оперативной памяти могут показаться излишними. Однако не так давно память объемом 1024 Кбайт (т. е. целый мегабайт!) удовлетворяла всех (или почти всех) пользователей персонального компьютера IMB PC. С широким внедрением персональных компьютеров в область обработки видеоинформации (в том числе в реальном времени) требования к объему оперативной памяти и быстродействию всех системы существенно возрастают. В любом случае уже сейчас многие приложения Windows соглашаются работать только в расширенном режиме.

    Илон Маск рекомендует:  Что такое код savedc

    Глобальная и локальная область памяти

    Свободное пространство в области стандартной памяти и расширенная память используются операционной системой Windows. Она как бы объединяет всю свободную память в одну глобальную область памяти (global heap ) и использует эту область для себя и для запуска приложений Windows.

    Помимо глобальной области памяти, для каждого приложения Windows выделяется собственная локальная область памяти (local heap ). Размер этой области ограничен величиной 64 Кбайт. Если для приложения требуются блоки памяти большего размера, оно может их получить из глобальной области памяти

    На практике глобальная память используется всегда, когда приложению требуется блок памяти размером, большим чем несколько Кбайт.

    Типы сегментов

    В операционной системе MS-DOS с точки зрения процессора все сегменты памяти были одинаковыми. Деление их на сегменты кода и сегменты данных достаточно условное, так как в MS-DOS нет никаких препятствий для того чтобы загрузить в CS:IP адрес любого сегмента, например, сегмента данных программы. Точно также программа могла выполнять любые операции в своем (или чужом) сегменте кода, или в сегменте, который принадлежит операционной системе. Так как в MS-DOS одновременно может работать только одна программа, вся оперативная память отдается ей в полное распоряжение.

    В мультизадачной операционной системе Windows память используется одновременно многими приложениями. Схема адресации защищенного режима эффективно защищает ядро Windows от приложений и позволяет в расширенном режиме увеличить размер глобальной области памяти за счет механизма виртуальной памяти.

    Однако для приложений нужны блоки памяти, занимающие непрерывное адресное пространство. Если в мультизадачной операционной системе не принимать никаких мер для уменьшения фрагментации адресного пространства, при интенсивной работе приложений очень скоро приложения не смогут получить непрерывный блок памяти даже при достаточном общем объеме свободной памяти.

    К счастью, операционная система Windows умеет объединять свободные блоки памяти, используя механизм перемещаемых (moveable ) и удаляемых (discardable ) сегментов.

    Операционная система Windows версии 3.0 могла работать как в реальном, так и в защищенном режиме. Перемещение блоков памяти в реальном режиме работы процессора представляет собой нетривиальную задачу, так как необходимо обеспечить работу приложения с блоками памяти, логический адрес которых может произвольно изменяться операционной системой в процессе перемещения. Эта проблема решалась с помощью двухступенчатой схемы получения доступа к блоку памяти.

    Согласно этой схеме на первом шаге получения доступа приложение заказывает для себя блок памяти, расположенный в фиксированном или перемещаемом сегменте. Фиксированный (fixed ) сегмент имеет постоянный логический адрес и не никогда не перемещается в адресном пространстве. Если ваше приложение заказывает для себя память при помощи функции malloc , она получает память в фиксированном сегменте.

    Блок памяти, расположенный в перемещаемом сегменте, не имеет постоянного логического адреса. При создании этот блок получает идентификатор, который и используется для ссылки. Windows может в любой момент времени переместить его в любое место адресного пространства для объединения свободных блоков памяти.

    Вы можете спросить, а как же пользоваться перемещаемым блоком памяти, не имеющим постоянного адреса?

    Очень просто, на втором шаге непосредственно перед использованием перемещаемый блок памяти необходимо зафиксировать, вызвав специальную функцию из программного интерфейса Windows.

    После использования блок памяти следует расфиксировать, для того чтобы Windows могла его перемещать.

    В защищенном режиме возможно перемещение зафиксированных блоков памяти, при этом их логический адрес не изменяется. Вместо этого изменяется базовый адрес в локальной таблице дескрипторов. Поэтому перемещение зафиксированных блоков памяти происходит для приложений незаметно. Это обстоятельство значительно упрощает приемы работы с сегментами.

    Таким образом, даже если ваше приложение, работающее в защищенном режиме, заказало фиксированный блок памяти, он все равно остается перемещаемым! Поэтому, создавая приложения для Windows версии 3.1 вы можете использовать фиксированные блоки памяти почти без ущерба для эффективности работы системы дефрагментации (так как логический адрес фиксированного блока не изменяется, это может привести к невозможности освобождения непрерывного пространства в таблице дескрипторов, нужного для адресации блоков памяти размером, большим 64 Кбайт).

    Если же вам и в самом деле необходимо получить блок памяти с фиксированным линейным адресом, придется вызывать специальную функцию GlobalFix , запрещающую изменение базового адреса в локальной таблице дескрипторов. Кроме того, если нужно обеспечить постоянное присутствие данного сегмента в физической памяти, для такого блока следует отключить механизм страничного обмена, вызвав функцию GlobalPageLock .

    Фиксирование линейного адреса и отмена страничного обмена — крайняя мера. Обычные приложения Windows не должны вызывать функции GlobalFix и GlobalPageLock, так как это может привести к снижению производительности работы операционной системы и приложений.

    Логический адрес перемещаемого блока памяти, состоящий из селектора и смещения, может произвольно изменяться операционной системой Windows. Для фиксирования блоков памяти в логическом адресном пространстве необходимо использовать функции GlobalLock или LocalLock.

    Операционная система Windows версии 3.1 перемещает зафиксированные блоки памяти, изменяя базовый адрес в локальной таблице дескрипторов, поэтому такое перемещение не приводит к изменению логического адреса и незаметно для приложений. Даже если приложение заказывает фиксированный блок памяти, но не вызывает функцию GlobalFix, этот блок памяти будет перемещаемым.

    Другой тип сегментов, предусмотренный в Windows, — удаляемые сегменты. В любой момент времени Windows может удалить сегмент из памяти, сохранив, однако, его идентификатор. Память, занимаемая ранее удаляемым сегментом, может быть использована Windows для других приложений.

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

    В файле определения модуля вы можете указать, что сегмент кода вашего приложения должен быть перемещаемым и удаляемым, а сегмент данных — перемещаемым. Для этого используются параметры moveable и discardable:

    В этом случае операционная система может перемещать память приложения и при необходимости удалять сегмент кода неактивного приложения из памяти. Если этот сегмент потребуется вновь, Windows самостоятельно загрузит его из exe-файла приложения.

    2.3. Работа с памятью в приложениях Windows

    В этом разделе мы расскажем вам о типах памяти, используемых приложениями Windows и о том, как приложения могут заказать для себя память.

    Глобальная динамическая память

    В Windows версии 3.1 область глобальной памяти общая для всех приложений Windows. Теоретически одно приложение может заказать для себя блок памяти из глобальной области и передать его идентификатор другому приложению, однако такая практика не приветствуется, так как в следующих версиях Windows адресные пространства приложений могут быть разделены (для передачи данных между приложениями необходимо использовать механизм динамической передачи данных DDE, который будет описан в одном из следующих томов «Библиотеки системного программиста»).

    Получение глобального блока памяти

    Для получения глобального блока памяти вы должны использовать функцию GlobalAlloc :

    Параметр fuAlloc определяет тип выделяемой памяти. Размер блока памяти в байтах должен передаваться через параметр cbAlloc, причем вы можете заказать блок памяти размером больше, чем 64 Кбайт. Для стандартного режима работы Windows можно заказать блок памяти размером до 1 Мбайт без 80 байт, для расширенного — до 16 Мбайт без 64 Кбайт.

    Функция возвращает идентификатор глобального блока памяти или NULL, если Windows не может выделить память указанного объема.

    Параметра fuAlloc должен быть указан как логическая комбинация следующих значений:

    Флаг Описание
    GMEM_DDESHARE Блок памяти будет использоваться совместно несколькими приложениями при помощи механизма динамического обмена данными DDE
    GMEM_DISCARDABLE Заказывается удаляемый блок памяти. Этот флаг должен использоваться совместно с флагом GMEM_MOVEABLE
    GMEM_FIXED Заказывается фиксированный блок памяти. Этот флаг несовместим с флагом GMEM_MOVEABLE.При работе в среде Windows версии 3.1 в защищенном режиме фиксированный сегмент, созданный с использованием флага GMEM_FIXED, является перемещаемым. Для такого сегмента в процессе перемещения логический адрес не изменяется, но линейный (и, следовательно, физический) может изменяться
    GMEM_LOWER Синоним для GMEM_NOT_BANKED. Не используется в Windows версии 3.1
    GMEM_MOVEABLE Заказывается перемещаемый блок памяти. Логический адрес перемещаемого блока памяти может изменяться. Этот флаг несовместим с флагом GMEM_FIXED
    GMEM_NOCOMPACT Для удовлетворения запроса памяти не следует выполнять объединение всех свободных участков памяти в один и удалять блоки памяти, отмеченные как удаляемые
    GMEM_NODISCARD Для удовлетворения запроса памяти не следует выполнять объединение всех свободных участков памяти в один
    GMEM_NOT_BANKED Получить блок памяти вне фрейма дополнительной памяти EMS. Не используется в Windows версии 3.1
    GMEM_NOTIFY Если заказанный объект будет удален, требуется вызов процедуры извещения. Процедура извещения назначается функцией GlobalNotify и должна располагаться в фиксированном сегменте кода в библиотеке DLL. С ее помощью приложение может разрешить или запретить Windows удалять блок данных
    GMEM_SHARE Синоним для GMEM_DDESHARE
    GMEM_ZEROINIT Во все байты блока необходимо записать нулевые значения
    GHDN Синоним для комбинации флагов GMEM_MOVEABLE и GMEM_ZEROINIT
    GPTR Синоним для комбинации флагов GMEM_FIXED и GMEM_ZEROINIT

    Идентификатор, полученный от функции GlobalAlloc, нельзя использовать для адресации памяти непосредственно. Напомним, что пока вы не зафиксировали блок памяти, его логический адрес недоступен.

    Приведем для примера фрагмент кода, в котором мы получаем перемещаемый блок памяти размером 200000 байт, причем во все байты полученного блока записываются нулевые значения:

    В следующем фрагменте мы заказываем удаляемый блок памяти размером 200000 байт, который никак не инициализируется:

    Фиксирование и расфиксирование блока памяти

    Для получения доступа к полученному блоку памяти его необходимо зафиксировать, вызвав функцию GlobalLock :

    Функция GlobalLock фиксирует блок памяти, идентификатор которого передается ей через параметр hglb и возвращает логический адрес зафиксированного блока или NULL, если указанный блок удален или произошла ошибка.

    В защищенном режиме работы Windows продолжает перемещать блоки памяти, зафиксированные функцией GlobalLock, изменяя базовый адрес в локальной таблице дескрипторов. Даже для фиксированных блоков памяти вызов этой функции все же необходим, потому что нужно получить логический адрес блока памяти.

    Для каждого блока памяти Windows поддерживает счетчик фиксирований. Этот счетчик увеличивается при вызове функции GlobalLock и уменьшается при расфиксировании блока функцией GlobalUnlock :

    Если содержимое счетчика уменьшилось до нуля, функция возвращает значение FALSE. В противном случае возвращается TRUE.

    Файл windowsx.h содержит макрокоманды, облегчающие работу с глобальными блоками памяти. Например, макрокоманда GlobalAllocPtr получает блок памяти и фиксирует его:

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

    Определение идентификатора блока памяти по его адресу

    С помощью функции GlobalHandle вы можете, зная селектор блока памяти, определить его идентификатор:

    Параметр uGlobalSel указывает селекторную компоненту логического адреса блока памяти.

    Младшее слово возвращаемого значения содержит идентификатор блока памяти, старшее — селектор блока памяти. В случае ошибки возвращается нулевое значение.

    В файле windowsx.h определена макрокоманда GlobalPtrHandle , упрощающая получение идентификатора блока памяти по его логическому адресу:

    Макрокоманда SELECTOROF определена в файле windows.h и предназначена для получения селекторной компоненты логического адреса:

    В файле windows.h есть также определения для макрокоманды OFFSETOF , возвращающей компоненту смещения, и макрокоманда MAKELP , конструирующая указатель из компонент смещения и селектора:

    Если вы работаете с транслятором Borland C++ for Windows, вместо этих макрокоманд можете использовать знакомые вам макрокоманды FP_SEG , FP_OFF и MK_FP , описанные в файле dos.h:

    Работа с удаляемыми блоками памяти

    Для того чтобы заказать удаляемый блок памяти, вы должны указать флаги GMEM_DISCARDABLE и GMEM_MOVEABLE , например:

    При необходимости Windows может удалить полученный таким образом блок из памяти, сохранив только его идентификатор, и использовать ранее распределенную этому блоку памяти для других приложений.

    При попытке зафиксировать удаленный блок с помощью функции GlobalLock приложение получит от этой функции значение NULL. В этом случае следует вызвать функцию GlobalFlags , предназначенную для определения состояния блока памяти, и проверить, находится ли данный блок в удаленном состоянии.

    Приведем прототип функции GlobalFlags:

    Функция возвращает состояние блока памяти, указанного своим единственным параметром. Младший байт возвращаемого значения содержит содержимое счетчика фиксаций блока памяти. В старшем байте могут быть установлены флаги GMEM_DISCARDABLE и GMEM_DISCARDED.

    Если установлен флаг GMEM_DISCARDABLE, проверяемый блок памяти может быть удален Windows в процессе дефрагментации свободной области памяти. Если же установлен флаг GMEM_DISCARDED, удаление блока памяти уже произошло.

    Для получения доступа к удаленному блоку памяти его необходимо восстановить, вызвав функцию GlobalReAlloc. Эта функция позволяет изменить характеристики существующего блока памяти.

    Приведем прототип функции GlobalReAlloc :

    Параметр hglb указывает идентификатор восстанавливаемого блока памяти.

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

    Параметр fuAlloc определяет тип восстановленного блока памяти. Можно указывать логическую комбинацию следующих флагов:

    Флаг Описание
    GMEM_DISCARDABLE Если блок памяти был перемещаемый, то теперь дополнительно он будет и удаляемый. Этот флаг должен использоваться совместно с флагом GMEM_MODIFY
    GMEM_MODIFY Выполняется изменение характеристик существующего блока памяти. этот флаг необходимо указывать вместе с флагами GMEM_DISCARDABLE и GMEM_MOVEABLE
    GMEM_MOVEABLE Если раньше указанный блок памяти был перемещаемым и удаляемым, содержимое счетчика фиксирования для него равно нулю и новый размер блока указан равным нулю, данный блок будет удален. Если же параметр cbNewSize равен нулю, но блок памяти не является перемещаемым или удаляемым, функция вернет признак ошибки.Для фиксированного блока памяти ненулевой длины данный флаг разрешает перемещение, т. е. преобразует фиксированный блок в перемещаемый.
    GMEM_NODISCARD Блок памяти не может быть удален операционной системой. Этот флаг должен использоваться совместно с флагом GMEM_MODIFY
    GMEM_ZEROINIT Если размер блока памяти увеличивается, во все байты дополнительной памяти необходимо записать нулевые значения. Этот флаг несовместим с флагом GMEM_MODIFY

    Восстановив блок памяти, вы должны зафиксировать его функцией GlobalLock и затем восстановить прежнее содержимое, так как после удаления от блока остался только идентификатор.

    Изменение блока памяти

    Как мы уже говорили, функция GlobalReAlloc , описанная выше, позволяет изменить характеристики глобального блока памяти.

    Если вам, например, надо изменить размер заказанного ранее блока памяти, сделав его равным 51200 байт, вы можете для этого использовать следующий фрагмент кода:

    После вызова функции блок памяти будет перемещаемый и удаляемый, причем если раньше его размер был меньше 51200 байт, во все байты дополнительной памяти будут записаны нулевые значения.

    Учтите, что при увеличении размера блока может возникнуть ситуация нехватки памяти, поэтому проверяйте значение идентификатора, возвращаемой функцией GlobalReAlloc, на неравенство константе NULL.

    Вы можете инициировать удаление блока памяти при помощи функции GlobalReAlloc, если укажите нулевой размер блока и флаг GMEM_MOVEABLE. В файле windows.h имеется определение макрокоманды GlobalDiscard, при помощи которой приложение может принудительно удалить блок из памяти:

    Определение размера блока памяти

    С помощью функции GlobalSize вы можете определить размер блока памяти по его идентификатору:

    Эта функция возвращает размер блока памяти, идентификатор которого задан параметром hglb. Если указанный блок памяти не существует или удален, возвращается нулевое значение.

    Дефрагментация памяти

    Если вызвать функцию GlobalCompact , операционная система Windows выполнит объединение всех свободных блоков в один. В качестве параметра этой функции необходимо указать требуемый размер непрерывного блока свободной памяти:

    Функция возвращает размер самого большого доступного непрерывного блока памяти, причем, если параметр на равен 0 или -1, выполняется дефрагментация памяти и удаление блоков, отмеченных как удаляемые. Если параметр функции указан как 0 или -1, функция не выполняет дефрагментацию памяти, но возвращает правильное значение с учетом возможного выполнения дефрагментации.

    Получение памяти в первом мегабайте адресного пространства

    Если у вас возникает необходимость заказать память, доступную приложениям MS-DOS, и располагающуюся в первом мегабайте адресного пространства, воспользуйтесь функцией GlobalDosAlloc :

    Параметр cbAlloc определяет размер блока в байтах.

    Старшее слово возвращаемого значения содержит сегментную компоненту адреса реального режима, соответствующего полученному блоку памяти. Это значение может использоваться для доступа к блоку памяти в реальном режиме работы процессора.

    Младшее слово возвращаемого значения содержит селектор для доступа к полученному блоку в защищенном режиме.

    Память, заказанная при помощи функции GlobalDOSAlloc, является фиксированной, поэтому вам не следует вызывать функцию GlobalLock для фиксирования и получения логического адреса.

    Для освобождения блока памяти, полученного при помощи функции GlobalDOSAlloc, следует вызвать функцию GlobalDosFree :

    В качестве параметра uSelector этой функции следует передать селекторную компоненту блока памяти, расположенного в первом мегабайте адресного пространства.

    В случае успешного завершения возвращаемое значение равно нулю. При ошибке возвращается селектор, указанный в параметре uSelector.

    Учтите, что заказывать памяти в первом мегабайте можно только в случае крайней необходимости, когда, вам, например, нужно обеспечить одновременный доступ к памяти со стороны приложений Windows и программ MS-DOS. Уменьшение свободного пространства в первом мегабайте адресного пространства отрицательно сказывается на производительности работы приложений Windows.

    Освобождение глобального блока памяти

    Для освобождения глобального блока памяти, полученного от функции GlobalAlloc, вы должны использовать функцию GlobalFree :

    Идентификатор освобождаемого блока передается функции в качестве ее единственного параметра.

    Функция возвращает NULL при успешном завершении или значение hglb при ошибке.

    Перед освобождением зафиксированных блоков памяти их следует предварительно расфиксировать. Вы можете узнать содержимое счетчика фиксаций блока при помощи функции GlobalFlags, описанной выше.

    Для освобождения памяти, полученной при помощи макрокоманды GlobalAllocPtr, удобно использовать макрокоманду GlobalFreePtr , описанную в файле windowsx.h:

    Данная макрокоманда расфиксирует, а затем и освобождает блок памяти, заданный своим логическим адресом.

    Фиксирование линейного адреса блока памяти

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

    Если драйвер какого-либо устройства ввода/вывода работает с линейным адресом буфера, память, отведенная для такого буфера в некоторых случаях должна быть зафиксирована функцией GlobalFix :

    Параметр функции указывает идентификатор фиксируемого блока памяти.

    Как только отпадет необходимость в фиксировании блока памяти, его следует расфиксировать, вызвав функцию GlobalUnfix :

    Единственный параметр этой функции должен содержать идентификатор блока памяти, который будет расфиксирован.

    Фиксирование страниц блока памяти

    В расширенном режиме работы операционной системы Windows версии 3.1 используется виртуальная память. Как мы уже говорили, при использовании виртуальной памяти вся глобальная область памяти делится на страницы размером 4 Кбайт. Эти страницы могут располагаться в физической оперативной памяти или на диске в специальном файле виртуальной памяти. Если приложение обращается к странице, которая отсутствует в физической оперативной памяти, она загружается туда из файла виртуальной памяти.

    Однако на загрузку страницы памяти из файла требуется значительное время. В некоторых случаях необходимо обеспечить постоянное присутствие блока памяти в физической оперативной памяти.

    Фиксирование блока памяти функцией GlobalFix не предотвращает сброс страниц памяти, распределенных блоку, в файл виртуальной памяти, а всего лишь запрещает перемещение блока памяти в линейном адресном пространстве.

    Для исключения страниц памяти, принадлежащих указанному блоку памяти, из процесса страничного обмена необходимо использовать функцию GlobalPageLock :

    Идентификатор блока, для которого необходимо запретить страничный обмен, указывается через параметр hglb.

    Операционная система Windows поддерживает счетчик блокирования страничного обмена. Содержимое этого счетчика увеличивается на единицу при каждом вызове функции GlobalPageLock.

    Функция GlobalPageLock возвращает новое значение счетчика или ноль при ошибке.

    Как только надобность в блокировке страничного обмена отпадает, следует вызвать функцию GlobalPageUnlock :

    Эта функция разрешает страничный обмен для блока памяти, заданного параметром hglb. Функция возвращает текущее значение счетчика или ноль при ошибке.

    Приложение GMEM

    Для демонстрации использования основных функций управления глобальной памятью мы приведем исходный текст приложения GMEM (листинг 2.3).

    Листинг 2.3. Файл gmem/gmem.cpp

    Перед началом работы приложение определяет объем свободной памяти, вызывая функцию GlobalCompact со значением параметра, равным -1. Определенное значение выводится на экран при помощи функции MessageBox.

    Далее приложение вызывает функцию GlobalCompact еще раз для освобождения непрерывного блока свободной памяти размером 100000 байт.

    После этого приложение заказывает буфер размером 100000 байт, вызывая функцию GlobalAlloc. В качестве первого параметра этой функции указана константа GHND, соответствующее перемещаемой памяти, инициализированной нулевым значением.

    В случае успешного получения блока памяти он фиксируется и на экран выводится значение идентификатора блока и его логический адрес. После этого в первый байт полученного блока записывается код символа ‘S’ и блок расфиксируется. При ошибке выдается сообщение.

    Далее полученный блок освобождается и возвращается операционной системе, для чего вызывается функция GlobalFree.

    После этого приложение заказывает удаляемый блок памяти размером 200000 байт и сразу же удаляет его, вызывая макрокоманду GlobalDiscard. Затем приложение предпринимает попытку зафиксировать только что удаленный блок памяти, вызывая функцию GlobalLock. Если блок памяти удалился успешно, функция GlobalLock должна вернуть значение NULL. В этом случае нам надо убедиться в том, что блок был удален, и если это так и есть, восстановить удаленный блок.

    Для проверки приложение использует функцию GlobalFlags. Если блок, идентификатор которого был передан этой функции в качестве параметра, удален, в возвращаемом значении установлен флаг GMEM_DISCARDED.

    Для восстановления удаленного блока приложение вызывает функцию GlobalReAlloc, указывая размер и характеристики блока. Затем восстановленный блок фиксируется в памяти и на экран выводится его идентификатор и логический адрес.

    Перед завершением работы приложения блок расфиксируется и освобождается.

    Файл определения модуля приложения GMEM приведен в листинге 2.4.

    Листинг 2.4. Файл gmem/gmem.def

    Локальная динамическая память

    Для каждого приложения Windows создается автоматический сегмент данных размером 64 Кбайт, в котором располагаются статические данные , стек и локальная область данных (local heap ). Кроме этого, автоматический сегмент данных имеет заголовок размером 16 байт (рис. 2.10).

    Рис. 2.10. Автоматический сегмент данных приложения Windows

    Размер стека определяется оператором STACKSIZE в файле определения модуля:

    Минимальный размер стека, назначаемый Windows для приложений, составляет 5 Кбайт. Следует отметить, что в руководстве к SDK нет точного описания способа определения минимально необходимого объема стека. В этом руководстве предлагается определить этот объем экспериментально, причем подчеркивается, что результаты переполнения стека непредсказуемы.

    В отличие от стека, размер локальной области данных может при необходимости увеличиваться автоматически. Начальное значение задается в файле определения модуля при помощи оператора HEAPSIZE :

    Вы можете указать любое отличное от нуля значение.

    Для работы с локальной областью данных программный интерфейс Windows содержит функции, аналогичные предназначенным для работы с глобальной областью данных.

    Получение локального блока памяти

    Для получения локального блока памяти вы должны использовать функцию LocalAlloc :

    Параметр fuAlloc определяет тип выделяемой памяти. Размер блока памяти в байтах должен передаваться через параметр cbAlloc.

    Функция возвращает идентификатор локального блока памяти или NULL, если Windows не может выделить память указанного объема.

    Параметра fuAlloc должен быть указан как логическая комбинация следующих значений:

    Флаг Описание
    LMEM_DISCARDABLE Заказывается удаляемый блок памяти. Этот флаг должен использоваться совместно с флагом LMEM_MOVEABLE
    LMEM_FIXED Заказывается фиксированный блок памяти (в защищенном режиме работы блок памяти будет перемещаемым, даже если он заказан с использованием флага LMEM_FIXED, однако в процессе перемещения будет изменяться только линейный адрес, но не логический). Этот флаг несовместим с флагом LMEM_MOVEABLE
    LMEM_MOVEABLE Заказывается перемещаемый блок памяти. Логический адрес такого блока может изменяться в процессе перемещения. Этот флаг несовместим с флагом LMEM_FIXED
    LMEM_NOCOMPACT Для удовлетворения запроса памяти не следует выполнять объединение всех свободных участков памяти в один и удалять блоки памяти, отмеченные как удаляемые
    LMEM_NODISCARD Для удовлетворения запроса памяти не следует выполнять объединение всех свободных участков памяти в один
    LMEM_ZEROINIT Во все байты блока необходимо записать нулевые значения
    NONZEROLHND Синоним для LMEM_MOVEABLE
    NONZEROLPTR Синоним для LMEM_FIXED
    LHDN Синоним для комбинации флагов LMEM_MOVEABLE и LMEM_ZEROINIT
    LPTR Синоним для комбинации флагов LMEM_FIXED и LMEM_ZEROINIT

    Приведем фрагмент кода, в котором мы получаем из локальной области памяти перемещаемый блок размером 2000 байт, причем во все байты полученного блока записываются нулевые значения:

    В следующем фрагменте мы заказываем удаляемый блок памяти размером 200 байт, который никак не инициализируется:

    Фиксирование и расфиксирование блока памяти

    Для получения доступа к полученному блоку памяти его необходимо зафиксировать, вызвав функцию LocalLock :

    Функция LocalLock фиксирует блок памяти, идентификатор которого передается ей через параметр hloc и возвращает логический адрес зафиксированного блока или NULL, если указанный блок удален или произошла ошибка.

    Так как операционная система Windows версии 3.1 работает только в защищенном режиме, все блоки памяти, зафиксированные при помощи функции LocalLock, будут перемещаемыми. Перемещение блоков памяти выполняется методом изменения базового адреса в локальной таблице дескрипторов, причем логический адрес перемещаемого блока остается неизменным. Поэтому перемещение фиксированных блоков памяти происходит для приложений незаметно.

    Для каждого блока памяти Windows поддерживает счетчик фиксирования. Этот счетчик увеличивается при вызове функции LocalLock и уменьшается при расфиксировании блока функцией LocalUnlock :

    Если содержимое счетчика уменьшилось до нуля, функция возвращает значение FALSE. В противном случае возвращается TRUE.

    Определение идентификатора блока памяти по его адресу

    С помощью функции LocalHandle вы можете определить идентификатор локального блока памяти:

    Параметр pvMem указывает адрес локального блока памяти.

    Возвращаемое значение содержит идентификатор локального блока памяти. В случае ошибки возвращается нулевое значение.

    Работа с удаляемыми блоками памяти

    Для получения доступа к удаленному локальному блоку памяти его необходимо восстановить, вызвав функцию LocalReAlloc. Эта функция аналогична функции GlobalReAlloc и позволяет изменить характеристики существующего блока памяти.

    Приведем прототип функции LocalReAlloc :

    Параметр hloc указывает идентификатор восстанавливаемого блока памяти.

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

    Параметр fuAlloc определяет тип восстановленного блок памяти. Можно указывать логическую комбинацию следующих флагов:

    Флаг Описание
    LMEM_DISCARDABLE Если блок памяти был перемещаемый, то теперь дополнительно он будет и удаляемый. Этот флаг должен использоваться совместно с флагом LMEM_MODIFY
    LMEM_MODIFY Выполняется изменение характеристик существующего блока памяти. этот флаг необходимо указывать вместе с флагами LMEM_DISCARDABLE и LMEM_MOVEABLE
    LMEM_MOVEABLE Если раньше указанный блок памяти был перемещаемым и удаляемым, содержимое счетчика фиксирования для него равно нулю и новый размер блока указан равным нулю, данный блок будет удален. Если же параметр cbNewSize равен нулю, но блок памяти не является перемещаемым или удаляемым, функция вернет признак ошибки.Для фиксированного блока памяти ненулевой длины данный флаг разрешает перемещение, т. е. преобразует фиксированный блок в перемещаемый.
    LMEM_NODISCARD Блок памяти не может быть удален операционной системой. Этот флаг должен использоваться совместно с флагом LMEM_MODIFY
    LMEM_ZEROINIT Если размер блока памяти увеличивается, во все байты дополнительной памяти необходимо записать нулевые значения. Этот флаг несовместим с флагом LMEM_MODIFY

    Восстановив блок памяти, вы должны зафиксировать его функцией LocalLock и затем восстановить его прежнее содержимое.

    Определение характеристик локального блока памяти

    Для определения характеристик локального блока памяти предназначена функция LocalFlags , аналогичная рассмотренной нами ранее функции GlobalFlags:

    Функция возвращает состояние блока памяти, указанного своим единственным параметром. Младший байт возвращаемого значения содержит содержимое счетчика фиксаций блока памяти. В старшем байте могут быть установлены флаги LMEM_DISCARDABLE и LMEM_DISCARDED.

    Если установлен флаг LMEM_DISCARDABLE, проверяемый блок памяти может быть удален Windows в процессе дефрагментации свободной области памяти. Если же установлен флаг LMEM_DISCARDED, удаление блока памяти уже произошло.

    Определение размера блока памяти

    С помощью функции LocalSize вы можете определить размер блока памяти по его идентификатору:

    Эта функция возвращает размер блока памяти, идентификатор которого задан параметром hloc. Если указанный блок памяти не существует или удален, возвращается нулевое значение.

    Илон Маск рекомендует:  Серверные скрипты введение

    Дефрагментация локального блока памяти

    Функция LocalCompact выполняет дефрагментацию свободного пространства в локальной области данных:

    Функция возвращает размер самого большого доступного непрерывного блока в локальной области памяти, причем, если параметр на равен 0 или -1, выполняется дефрагментация памяти и удаление блоков, отмеченных как удаляемые. Если параметр функции указан как 0, функция не выполняет дефрагментацию памяти, но возвращает правильное значение с учетом возможного выполнения дефрагментации.

    Уменьшение размера локального блока памяти

    Для уменьшения размера существующего локального блока памяти можно использовать функцию LocalShrink :

    Параметр hloc указывает идентификатор изменяемого локального блока памяти. Новые размеры блока памяти задаются параметром cbNewSize.

    Возвращаемое значение в случае успеха равно новому размеру блока памяти.

    В процессе получения памяти при помощи функции LocalAlloc размер использованной локальной памяти будет расти, пока не достигнет 64 Кбайт. После освобождения локальных блоков данных размер локальной области не уменьшится сам по себе. Для восстановления этого размера вы должны вызвать функцию LocalShrink.

    Освобождение локального блока памяти

    Для освобождения локального блока памяти, полученного от функции LocalAlloc, вы должны использовать функцию LocalFree :

    Идентификатор освобождаемого блока передается функции в качестве ее единственного параметра.

    Функция возвращает NULL при успешном завершении или значение hloc при ошибке.

    Перед освобождением зафиксированных блоков памяти их следует предварительно расфиксировать.

    Инициализация локальной области данных в заданном сегменте

    Для создания и инициализации локальной области данных в заданном сегменте вы можете воспользоваться функцией LocalInit :

    Параметр uSegment перед вызовом функции должен содержать идентификатор сегмента, который будет содержать локальную область данных.

    Параметр uStartAddr определяет начальный адрес локальной области данных, а параметр uEndAddr — конечный адрес локальной области данных.

    Первые 16 байт в сегменте данных необходимо зарезервировать для системы.

    Приложение LMEM

    Приведем исходный текст приложения LMEM, которое работает аналогично приложению GMEM, но с использованием локальной области памяти (листинг 2.5).

    Листинг 2.5. Файл lmem/lmem.cpp

    Файл определения модуля приложения LMEM приведен в листинге 2.6.

    Листинг 2.6. Файл lmem/lmem.def

    В этом файле начальное значение локальной области данных установлено равным 4096 байт. Проверяя работу приложения LMEM, вы можете попробовать уменьшить размер локальной области данных, например, до величины 1 Кбайт, а затем заказать локальный блок памяти размером 10 Кбайт. В этом случае несмотря на то, что сразу после запуска приложения в локальной области данных будет свободно всего несколько сотен байт, запрос на 10 Кбайт будет удовлетворен за счет автоматического увеличения размера локальной области данных.

    Статическая память

    Статические данные, описанные в приложении Windows с использованием ключевого слова static или объявленные как внешние переменные располагаются в автоматическом сегменте данных приложения (рис. 2.10).

    В документации к SDK не рекомендуется в моделях памяти small и medium использовать дальние указатели на статические данные (См. раздел 16.5 руководства, который называется Traps to Avoid When Managing Program Data).

    Дело в том, что автоматический сегмент данных приложения является перемещаемым. Операционная система Windows фиксирует сегмент данных при активизации приложения и расфиксирует его во время переключения на другие приложения. Поэтому логический адрес сегмента данных может изменяться.

    Следующий способ является недопустимым:

    В фрагменте кода, приведенном выше, содержимое указателя lpstrDlgName устанавливается загрузчиком. В руководстве отмечается, что в процессе перемещения сегмента значение указателя может измениться (так как при перемещении сегмента может измениться значение селектора), что приведет к ошибке.

    Рекомендуется в указанной выше ситуации использовать ближний статический указатель с явным преобразованием типа к LPSTR:

    В процессе явного преобразования типа используется текущее содержимое регистра DS, а не то, которое использовалось при загрузке приложения в память.

    Автоматическая память

    Автоматические данные располагаются, как и статические, в автоматическом сегменте данных (рис. 2.10), назначаемым приложению при его загрузке в память. К автоматическим данным относится стек, параметры функций и локальные переменные.

    Как мы уже говорили, размер стека определяется оператором STACKSIZE в файле определения модуля и не увеличивается автоматически во время работы приложения.

    Дополнительная память в структуре класса окна

    При регистрации класса окна вы можете в поле cbClsExtra структуры WNDCLASS указать размер дополнительной области памяти, которая будет зарезервирована в структуре данных, описывающей класс окна. В эту область можно записать данные, предназначенные для использования всеми окнами, создаваемыми на базе класса.

    Для работы с этой дополнительной памятью предназначены функции SetClassWord, SetClassLong, GetClassWord, GetClassLong.

    Функция SetClassWord устанавливает в структуре, описывающей класс для окна hwnd, новое значение wNewWord, при этом смещение устанавливаемого слова определяется параметром offset:

    Для параметра offset вы должны использовать значения от нуля до указанного в поле cbClsExtra минус 2 или следующие значения:

    Значение Описание
    GCW_HBRBACKGROUND Идентификатор кисти для закрашивания фона окна
    GCW_HCURSOR Идентификатор курсора
    GCW_HICON Идентификатор пиктограммы
    GCW_STYLE Стили окна

    С помощью перечисленных выше четырех значений вы можете изменить характеристики класса окна. Эти изменения будут учитываться только для вновь создаваемых окон.

    В случае ошибки функция SetClassWord возвращает нулевое значение.

    Функция GetClassWord позволяет вам прочитать содержимое слова дополнительной области памяти со смещением offset:

    Для этой функции вы можете использовать те же значения, что и для предыдущей, плюс еще два:

    Значение Описание
    GCW_CBCSLEXTRA Размер дополнительной области памяти в структуре класса окна
    GCW_CBWNDEXTRA Размер дополнительной области памяти в структуре окна
    GCW_HBRBACKGROUND Идентификатор кисти для закрашивания фона окна
    GCW_HCURSOR Идентификатор курсора
    GCW_HICON Идентификатор пиктограммы
    GCW_STYLE Стили окна

    Функция GetClassWord возвращает значение указанного слова из структуры класса окна или нулевое значение при ошибке.

    Функция SetClassLong аналогична функции SetClassWord, но работает с двойными словами:

    Для параметра offset дополнительно можно указать значение GCL_WNDPROC, при этом функция заменит адрес функции окна. Мы пользовались этим приемом в приложении SMARTPAD, перехватывая управление у стандартной функции окна органа управления класса «edit».

    В случае ошибки функция SetClassLong возвращает нулевое значение.

    С помощью функции GetClassLong вы можете получить из структуры класса окна значение двойного слова, расположенного со смещением offset:

    Для этой функции можно указать положительное смещение или одну из двух констант — GCL_WNDPROC и GCL_MENUNAME. В первом случае функция GetClassLong возвратит адрес функции окна для данного класса, во втором — указатель на строку имени меню, указанного при регистрации класса.

    Дополнительная память в структуре окна

    При регистрации класса окна функцией RegisterClass вы можете в поле cbWndExtra структуры WNDCLASS указать размер дополнительной области памяти, которая будет зарезервирована в структуре, описывающей каждое окно, создаваемое на базе данного класса.

    Для работы с этой дополнительной памятью предназначены функции SetWindowWord, SetWindowLong, GetWindowWord, GetWindowLong.

    Функция SetWindowWord устанавливает в структуре, описывающей окно hwnd, новое значение wNewWord, при этом смещение устанавливаемого слова определяется параметром offset:

    Для параметра offset вы должны использовать значения от нуля до указанного в поле cbClsExtra минус 2 или следующие значения:

    Значение Описание
    GWW_HINSTANCE Идентификатор приложения, владеющего данным окном
    GWW_ID Идентификатор дочернего окна

    В случае ошибки функция SetWindowWord возвращает нулевое значение.

    Функция GetWindowWord позволяет вам прочитать содержимое слова дополнительной области памяти в структуре окна со смещением offset:

    Для этой функции вы можете использовать следующие значения:

    Значение Описание
    GWW_HINSTANCE Идентификатор приложения, владеющего данным окном
    GWW_HWNDPARENT Идентификатор родительского окна
    GWW_ID Идентификатор дочернего окна

    Функция GetWindowWord возвращает значение указанного слова из структуры класса окна или нулевое значение при ошибке.

    Функция SetWindowLong аналогична функции SetWindowWord, но работает с двойными словами:

    Для параметра offset дополнительно можно указать следующие значения:

    Значение Описание
    GWL_EXSTYLE Расширенный стиль окна
    GWL_STYLE Стиль окна
    GWL_WNDPROC Указатель на функцию окна

    Если параметр hwnd содержит идентификатор диалоговой панели, вы можете использовать еще несколько значений:

    Значение Описание
    DWL_MSGRESULT Значение, возвращенное при обработке сообщения в функции диалоговой панели
    DWL_USER Дополнительная информация, имеющая отношение к приложению, такая как идентификаторы или указатели
    DWL_DLGPROC Указатель на функцию диалоговой панели

    В случае ошибки функция SetWindowLong возвращает нулевое значение.

    С помощью функции GetWindowLong вы можете получить из структуры окна значение двойного слова, расположенного со смещением offset:

    Для этой функции можно указать положительное смещение или одну из констант, описанных выше для функции SetWindowLong .

    Ресурсы приложения

    Управление ресурсами было рассмотрено нами в предыдущем томе «Библиотеки системного программиста». Как вы знаете, ресурсы представляют собой данные, расположенные в файле загрузочного модуля приложения и доступные только для чтения.

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

    Загрузка ресурсов в оперативную память выполняется такими функциями, как LoadIcon или CreateDialog . Для загрузки ресурсов, имеющих нестандартный формат, вы должны использовать функции FindResource (поиск ресурса и получение идентификатора ресурса) и LoadResource (загрузка ресурса и получение идентификатора блока памяти, в который загружен найденный ресурс).

    Все эти функции были описаны в предыдущем томе, однако для удобства мы приведем их краткое описание еще раз.

    Приведем прототип функции FindResource :

    Параметр hInst является идентификатором модуля, содержащего ресурс. Для извлечения ресурса из приложения вы должны указать его идентификатор, передаваемый функции WinMain через параметр hInstance.

    Параметр lpszName должен содержать адрес имени ресурса. Для загрузки произвольных данных в качестве этого параметра следует передать указатель на строку, содержащую идентификатор ресурса.

    Функции FindResource в качестве третьего параметра можно передавать идентификаторы предопределенных типов ресурсов, список которых приведен ниже.

    Идентификатор ресурса Название ресурса
    RT_ACCELERATOR Таблица акселераторов
    RT_BITMAP Изображение bitmap
    RT_CURSOR Курсор
    RT_DIALOG Диалоговая панель
    RT_FONT Шрифт
    RT_FONTDIR Каталог шрифтов
    RT_ICON Пиктограмма
    RT_MENU Меню
    RT_RCDATA Произвольные данные
    RT_STRING Таблица строк

    Вы можете использовать функцию FindResource для загрузки таких ресурсов, как пиктограммы или курсоры, указав ей тип ресурса, соответственно, RT_ICON или RT_CURSOR. Однако в документации к SDK сказано, что загрузку предопределенных ресурсов, таких как пиктограммы и курсоры, следует выполнять специально предназначенными для этого функциями (LoadIcon, LoadCursor и т. д.).

    После того как ресурс найден, его следует загрузить, вызвав функцию LoadResource :

    Параметр hinst представляет собой идентификатор модуля, из файла которого загружается ресурс. Если ресурс загружается из файла вашего приложения, используйте значение hInstance, полученное через соответствующий параметр функции WinMain.

    В качестве второго параметра этой функции следует передать значение, полученное от функции FindResource.

    Для получения логического адреса загруженного ресурса его необходимо зафиксировать в памяти, вызвав функцию LockResource :

    В качестве параметра hGlb функции LockResource следует передать идентификатор ресурса, полученный от функции LoadResource.

    Функция LockResource фиксирует данные в памяти и возвращает дальний указатель на соответствующий буфер. После фиксирования Windows не станет удалять сегмент с ресурсами из памяти, так что приложение сможет использовать данные в любой момент времени.

    После того как приложение использовало ресурс и он стал ненужен, следует расфиксировать память ресурса, вызвав функцию UnlockResource . Функция определена через функцию GlobalUnlock следующим образом:

    Перед завершением работы приложения следует освободить полученный ресурс, вызвав функцию FreeResource :

    В качестве параметра hGlb следует передать идентификатор ресурса, полученный от функции LoadResource.

    2.4. Функция malloc и farmalloc

    Для получения блока памяти приложения Windows могут использовать функцию malloc.

    Выделенный блок памяти будет автоматически зафиксирован.

    С помощью этой функции вы, однако, не сможете получить блок памяти размером большим, чем 64 Кбайт, так как тип size_t отображается на 16-разрядное целое.

    Блоки памяти, полученные с помощью функции malloc, необходимо освобождать функцией free , указывая ей адрес освобождаемого блока памяти:

    Если вам надо получить большой блок памяти, можно воспользоваться функцией farmalloc , которая входит в состав стандартной библиотеки Borland C++:

    Так как параметр этой функции, определяющий размер заказываемого блока памяти, имеет тип unsigned long, вы можете запрашивать блоки памяти очень большого размера. Возвращаемое этой функцией значение следует преобразовывать в указатель типа huge. В этом случае с использованием такого указателя вы сможете напрямую адресовать любой участок большого блока памяти.

    Освобождение блока памяти, полученного при помощи функции farmalloc, должно выполняться функцией farfree :

    В некоторых случаях использование функции farmalloc может оказаться предпочтительней, чем использование функции GlobalAlloc.

    Как вы знаете, локальная таблица дескрипторов может содержать не более чем 8192 дескриптора. Значительная часть локальной таблицы дескрипторов, которая в Windows версии 3.1 одна на все приложения, может быть занята самой операционной системой или другими приложениями. Если ваше приложение заказывает большое количество глобальных блоков памяти, используя функцию GlobalAlloc, таблица дескрипторов может быстро переполниться, так как для каждого блока памяти в локальной дескрипторной таблице создается отдельный дескриптор.

    Для функции farmalloc используется другой метод. В локальной таблице дескрипторов создается один дескриптор, который адресует область памяти, используемую одновременно для выделения нескольких блоков памяти. Например, если вы заказали блок памяти размером 100 Кбайт, а затем из них освободили 50 Кбайт, при повторном запросе памяти она будет выделена из заказанного ранее блока без создания нового дескриптора. Таким образом, функция farmalloc позволяет экономить свободное пространство в локальной таблице дескрипторов.

    2.5. Работа с локальной таблицей дескрипторов

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

    Функция AllocSelector позволяет создать в локальной таблице дескрипторов новый дескриптор или скопировать существующий:

    Если параметр uSelector перед вызовом функции содержит селектор, для которого в таблице дескрипторов есть дескриптор, функция AllocSelector копирует этот дескриптор и возвращает селектор, соответствующий копии. Если же этот параметр равен нулю, в локальной таблице дескрипторов создается новый неинициализированный дескриптор, при этом функция возвращает значение селектора, соответствующее созданному дескриптору. При ошибке возвращается нулевое значение.

    Если созданный дескриптор больше не нужен, его следует удалить при помощи функции FreeSelector :

    Параметр функции должен содержать селектор, соответствующий удаляемому дескриптору. Если функция выполнилась без ошибок, она возвращает нулевое значение. В случае ошибки возвращается значение параметра uSelector.

    Перед использованием нового дескриптора его следует проинициализировать — установить базовый адрес и предел.

    Для установки базового адреса следует воспользоваться функцией SetSelectorBase , которая впервые появилась в составе программного интерфейса Windows версии 3.1:

    Для дескриптора, соответствующего селектору uSelector, устанавливается значение линейного адреса, равное dwBase.

    Если функция выполнилась успешно, она возвращает значение параметра uSelector. В случае ошибки возвращается нулевое значение.

    С помощью функции GetSelectorBase вы можете определить линейный адрес для любого существующего селектора:

    При помощи функции SetSelectorLimit вы можете определить предел сегмента, адресуемого селектором uSelector:

    Предел сегмента задается параметром dwLimit. Для процессора 80286 предел не должен превосходить величины 0x10000. О пределах сегментов вы можете прочитать в шестом томе «Библиотеки системного программиста», который называется «Защищенный режим процессоров Intel 80286/80386/80486».

    Функция GetSelectorLimit позволяет вам для заданного селектора uSelector определить предел сегмента:

    С помощью функции LockSegment вы можете зафиксировать сегмент, соответствующий селектору uSelector:

    Если в качестве параметра этой функции передать значение -1, функция зафиксирует текущий сегмент данных.

    Возвращаемое значение определяет зафиксированный сегмент данных или NULL, если сегмент был удален или произошла ошибка.

    После использования зафиксированный сегмент необходимо расфиксировать при помощи функции UnlockSegment :

    В файле windows.h определены макрокоманды LockData и UnlockData , предназначенные, соответственно, для фиксирования и расфиксирования текущего сегмента данных:

    Если вам необходимо выполнить код, расположенный в сегменте данных, вы можете выполнить преобразование селекторов, вызвав функцию AllocDStoCSAlias :

    В качестве параметра этой функции передается селектор сегмента данных, содержащего код. Функция создает новый дескриптор, описывающий данный сегмент как сегмент кода и возвращает соответствующий селектор. После использования полученный селектор следует освободить при помощи функции FreeSelector.

    Функция PrestoChangoSelector создает селектор кодового сегмента, соответствующий селектору сегменту данных или наоборот, селектор сегмента данных, соответствующий сегменту кода:

    Параметр sourceSel задает исходный селектор, который будет преобразован.

    Параметр destSel задает селектор, полученный при помощи функции AllocSelector. Дескриптор, соответствующий этому селектору, получит новые значения атрибутов, которые будут соответствовать атрибутам преобразуемого селектора.

    2.6. Работа с большими массивами данных

    С помощью функции GlobalAlloc приложения могут заказать блок памяти, превосходящий по своим размерам 64 кбайт. Операционная система разделяет такие блоки памяти на участки размером не более 64 Кбайт, причем для адресации всех этих участков используется несколько дескрипторов, расположенных друг за другом (рис. 2.11).

    Рис. 2.11. Адресация большого блока памяти

    В процессе выделения приложению большого блока памяти Windows может передвигать дескрипторы перемещаемых сегментов для освобождения нужного количества ячеек таблицы дескрипторов, расположенных рядом.

    Для работы с блоками памяти размером более 64 Кбайт приложения, составленные на языках программирования С и С++ должны использовать указатели типа huge . Для таких указателей переключение селекторов, необходимое для получения доступа ко всему блоку памяти, выполняется автоматически.

    Если вам потребуется создать приложение Windows или его отдельный модуль на языке ассемблера при помощи MASM, вы можете использовать значение __AHINCR для определения величины, которую нужно прибавить к селектору для того чтобы получить значение селектора, соответствующего следующему дескриптору.

    Если вы в приложении Windows определяете данные с помощью ключевого слова huge, указатели на эти данные следует использовать с осторожностью. Несмотря на то, что все операции с указателями huge будут выполняться правильно, при передаче таких указателей функциям из программного интерфейса Windows могут возникнуть ошибки, если эти функции, изменяя полученный указатель, пересекут границу 64 Кбайт.

    2.7. Утилита HEAPWALK

    В составе SDK имеется утилита HEAPWALK , с помощью которой вы можете выполнить анализ содержимого глобальной области памяти. Для любого модуля, загруженного в память (приложения или библиотеки DLL) эта утилита показывает адреса, идентификаторы, размеры и атрибуты блоков памяти. С помощью этой утилиты вы можете проследить за тем, как ваше приложение работает с глобальной областью памяти. Вы можете обнаружить в отлаживаемом приложении часто встречающуюся ошибку, когда оно (приложение) не освобождает полученные им блоки памяти.

    Главное окно утилиты HEAPWALK представлено на рис. 2.12.

    Рис. 2.12. Главное окно утилиты HEAPWALK

    В главном окне находится список, каждая строка которого соответствует одному блоку памяти.

    В столбцах списка отображается следующая информация (все численные значения выражаются шестнадцатеричными цифрами):

    Название Описание
    ADDRESS Адрес блока памяти
    HANDLE Идентификатор блока памяти
    SIZE Размер блока памяти в байтах
    LOCK Содержимое счетчика фиксирования блока памяти. Если для блока памяти запрещен страничный обмен, в этом поле есть буква «P». Если блок памяти зафиксирован и не может быть удален, он обозначается буквой «L»
    FLG Если блок памяти удаляемый (discardable), в этом поле находится буква «D», если фиксированный — буква «F»
    HEAP Если объект имеет локальную область памяти, в этом столбце находится буква «Y»
    OWNER Имя модуля (или приложения), владеющего блоком памяти
    TYPE Тип объекта (сегмент кода, сегмент данных, ресурс и т. д.)

    С помощью меню «Walk» вы можете выбрать один из трех режимов просмотра глобальной области памяти, выполнить дефрагментацию памяти, запросить удаление удаляемых блоков данных и т. д.

    Если в меню «Walk» выбрать строку «Walk Heap», в главном окне утилиты HEAPWALK будет отображаться информация о всех объектах, расположенных в глобальной области памяти.

    Для того чтобы просмотреть все удаляемые объекты, выберите из этого меню строку «Walk LRU List». Те объекты, которые давно не использовались, будут расположены в верхней части списка.

    Если выбрать из меню «Walk» строку «GC(0) and Walk», утилита выполнит дефрагментацию глобальной области памяти, запросит блок памяти размером 0 байт и отобразит список объектов.

    С помощью строки «GC(-1) and Walk» вы можете предпринять попытку удалить все удаляемые сегменты и просмотреть список объектов.

    Остальные строки меню «Walk» описаны в руководстве по утилитам, входящим в состав SDK.

    Для удобства отображения вы можете отсортировать блоки памяти в списке при помощи меню «Sort». С помощью этого меню можно выполнить сортировку по адресам блоков памяти (строка «Address» меню «Sort»), по именам модулей, которым принадлежат блоки памяти (строка «Module»), по размеру блоков памяти (строка «Size»), типу объектов (строка «Type»). С помощью строки «Refresh Seg Names» вы можете просмотреть имена сегментов, загруженных в память после запуска утилиты HEAPWALK.

    Вы можете выбрать любую строку в списке объектов и просмотреть соответствующий ему блок памяти с помощью меню «Object».

    Строка «Show» меню «Object» позволяет просмотреть содержимое блока памяти в виде шестнадцатеричного дампа памяти или ресурса (пиктограммы, изображения bitmap, меню, диалоговой панели и т. д.). На рис. 2.13 в окне «Resource Bitmap» можно увидеть изображение пиктограммы, соответствующей выбранному блоку памяти.

    Рис. 2.13. Просмотр пиктограммы

    С помощью строки «Discard» можно удалить выбранный объект из памяти.

    Объект может быть отмечен как ближайший кандидат на удаление (строка «Oldest») или как объект, который должен быть удален в последнюю очередь (строка «Newest»).

    Строка «LocalWalk» позволяет вам просмотреть локальную область памяти для выбранного объекта (если у этого объекта есть локальная область памяти). Эта область памяти отображается в отдельном окне (рис. 2.14).

    Рис. 2.14. Просмотр локальной области памяти

    С помощью меню «Alloc» вы можете заказывать всю свободную память (строка «Allocate All of Memory») и освобождать блоки памяти различного размера (строки «Free All», «Free 1K», . «Free 50K», «Free XK»).

    2.8. Модели памяти

    Для приложений Windows вы можете выбрать одну из четырех моделей памяти: small, medium, compact или large.

    Все приложения, рассмотренные нами ранее, были подготовлены в модели памяти small. Для этой модели при загрузке приложения в память создается два сегмента — сегмент кода и автоматический сегмент данных. Перед тем как передать управление приложению, Windows записывает адрес сегмента кода в регистр CS, адрес автоматического сегмента данных — в регистры DS и SS. Таким образом, в этой модели памяти для стека и автоматического сегмента данных используется один и тот же сегмент.

    Сегмент кода, так же как и сегмент данных, может быть перемещаемым и удаляемым. Соответствующие атрибуты указываются в файле определения модуля при помощи операторов CODE и DATA:

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

    Для сложных приложений Windows удобно использовать модель памяти medium, в которой создается один сегмент данных и несколько сегментов кода. Однако вызов дальней функции (а в модели памяти medium все функции вызываются как дальние) выполняется дольше, чем в MS-DOS. Это связано с наличием в Windows механизма перемещения сегментов.

    Чаще, однако, работают со смешанными моделями памяти, используя при описании функций и данных ключевые слова FAR и NEAR. Заметим, что даже если ваше приложение было подготовлено в модели памяти small, оно на самом деле пользуется смешанной моделью памяти, так как все функции программного интерфейса Windows определены как дальние.

    Вы можете также использовать модели памяти compact (один сегмент кода и несколько сегментов данных) и large (несколько сегментов кода и несколько сегментов данных). Но для этих моделей есть одно существенное ограничение — можно запускать только одну копию приложения, созданного с использованием таких моделей памяти. Если запустить несколько приложений, созданных, например, в модели памяти large, для каждой копии приложения будет создан свой автоматический сегмент, но все остальные сегменты кода и данных будут существовать в единственном экземпляре и адресоваться всеми копиями приложения. Иными словами, все копии приложения будут иметь общие сегменты кода и данных (исключая автоматический сегмент).

    Если ваше приложение создано в модели памяти medium, имеет смысл сгруппировать различные функции в несколько сегментов и для каждого сегмента определить свои атрибуты. Например, функции инициализации приложения следует расположить в сегменте с атрибутами PRELOAD и DISCARDABLE. В этом случае эти функции будут загружены в памяти в процессе запуска приложения и впоследствии будут удалены. Функции, обрабатывающие сообщения, должны быть загружены в память при инициализации приложения и находиться там постоянно, поэтому для них подойдет атрибут PRELOAD. Те функции, которые требуются эпизодически, можно загружать при необходимости и удалять после использования, поэтому для них следует указать атрибуты LOADONCALL и DISCARDABLE.

    Для назначения атрибутов сегментам приложения файл определения модуля должен содержать оператор SEGMENTS:

    Для изменения имени сегмента кода в системах разработки Borland C++ версии 3.1 и Borland C++ for Windows версии 4.01 можно использовать параметр командной строки -zCname, где name — новое имя сегмента кода. По умолчанию сегмент кода имеет имя _TEXT. Для того чтобы восстановить имя сегмента кода, можно использовать параметр -zC*.

    Параметры командной строки могут быть указаны непосредственно в исходном тексте приложения с помощью ключевого слова #pragma options :

    Если вы создаете приложения с помощью Microsoft C++ версии 7.0 или Microsoft Visual C++, исходные тексты всех функций, которые должны находиться в одном сегменте, следует расположить в одном файле. Для изменения имени сегмента следует воспользоваться параметром /NT:

    Все о кодах сопряжения

    Мы недавно опубликовали пост о правилах безопасности кошелька, но вопросы безопасности настолько разнообразны, что изложить все в одном посте практически невозможно.

    Кроме идентификатора и пароля, кошелек содержит и другую важную информацию, которую следует сохранять втайне. Этот пост рассказывает о кодах сопряжения, предназначенных для доступа к кошельку через мобильное приложение.

    Что такое код сопряжения?

    Код сопряжения — это уникальный код, который дает доступ к кошельку на нескольких устройствах одновременно. Это обеспечивает удобный и быстрый вход в кошелек без повторной загрузки с каждого устройства вручную. Коды бывают в форматах PIN (из нескольких цифр) и штрих QR (Quick Response), как в кошельке Blockchain. Вы можете найти Ваш код сопряжения, войдя в кошелек и пройдя в Настройки > Информация о Кошельке и нажав на “Показать код сопряжения.”

    Зачем использовать код?

    Как мы уже отметили, код сопряжения предоставляет быстрый доступ к кошельку с дополнительных устройств. Если Вы обычно используете кошелек на вебе, но хотите также иметь возможность воспользоваться кошельком на мобильном телефоне, скачайте наше приложение для Андроида или iOS и отсканируйте код сопряжения, показанный в Вашем кошельке.

    Кошелек тогда будет доступен на обоих устройствах и будет отображать все Ваши транзакции. Таким образом Вы сможете отправлять и получать средства используя любое устройство.

    Никогда не выдавайте Ваш код сопряжения

    Поскольку код сопряжения дает полный доступ к кошельку и находящимся в нем средствам, очень важно сохранять его втайне, и ни в коем случае, никогда и никому его не сообщать. Любой человек, у которого есть Ваш код сопряжения, сможет воспользоваться Вашими средствами, даже не зная идентификатора и пароля кошелька и не имея Ваших кодов двухфакторной верификации. Выдавая код сопряжения, Вы выдаете неограниченный доступ к Вашим средствам, восстановительной фразе и истории транзакций.

    Коды сопряжения и фишинг

    К сожалению, мошенники тоже обратили внимание на наши коды сопряжения. Они могут выступать от имени нашей службы поддержки и просить сообщить Ваш код или восстановительную фразу для решения каких-то проблем, или создают сайты похожие на наш, которые обещают инвестиции. Наша команда поддержки никогда не попросит Вас отправить код сопряжения или восстановительную фразу.

    Чтобы защититься от таких мошенников, просите о помощи только через официальный сайт поддержки . Наша команда не предоставляет поддержку через личные сообщения на социальных сетях.

    Вы можете следить за объявлениями и новостями на нашей странице ВКонтакте .

    Есть дополнительные вопросы о кодах сопряжения?

    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL