![Sound Recorder](https://habrastorage.org/getpro/habr/post_images/e3f/97c/f08/e3f97cf088915ba87f9e55f1ee79e4de.png)
Когда небо было голубее, Солнце светило ярче, а Интернет был таким недоступным… Короче, в далеком детстве мне почему-то полюбилась стандартная программа «Звукозапись» из Windows 98. Не глядя на минимальную функциональность, я даже умудрялся делать в ней простейшие «ремиксы» ей же записанных мелодий из игр.
Шли годы. Железо становилось мощнее, а ОС функциональнее. Но «Звукозапись» не менялась. Даже в Windows XP она оставалась такой же, как и тогда. Пришло время обновить железо. 3 гигабайта оперативной памяти — раньше и мечтать о таком не приходилось. Этого уж точно должно хватить всем! Так и было, пока дело не дошло до той самой «Звукозаписи». После попытки записать небольшой звук программа невозмутимо возразила, что ей недостаточно оперативной памяти.
![Not enough memory available to complete this operation. Quit one or more applications to increase available memory, and then try again.](https://habrastorage.org/getpro/habr/post_images/504/843/a22/504843a22b671bfd23357f6a4bd3cfd4.png)
Что конечно же возмутило меня. Закрыл все программы, попробовал перезагрузиться — не помогло. Страшная мысль о проблеме в программе закралась в голову, и мои опасения оправдались: Microsoft заявляет, что при наличии более 2 гигабайт оперативной памяти программа сообщает о её недостаче, и это особенность архитектуры приложения. Причем не предлагается никакого адекватного способа решения проблемы, кроме уменьшения объема физически доступной памяти. Как говорится, пользуйтесь тем что есть.
![](https://habrastorage.org/getpro/habr/post_images/460/aca/656/460aca656c59c9170eaa99e9d972ea7d.png)
Вопреки просьбе «Звукозаписи» завершить ненужные приложения, я постарался занять побольше свободной оперативной памяти. Как ни странно, как только отметка свободной памяти упала ниже двух гигабайт, ошибка исчезла.
Очевидно, что в коде проверки количества свободной памяти разработчик объявил переменную:
int AvailableMemory;
Из-за чего число свободных байт рассматривается как знаковое число. При объеме свободной памяти больше двух гигабайт, первый бит устанавливается в единицу, поэтому число выглядит как отрицательное. Для исправления ошибки достаточно было бы написать: unsigned int AvailableMemory;
Но Microsoft этого не делает, вероятно, для стимуляции перехода на Windows Vista или 7 (шутка), где «Звукозапись», увы, уже совсем другая программа. ![](https://habrastorage.org/getpro/habr/post_images/0da/ae7/9db/0daae79db810eba24d96972d7b8080a3.png)
Так что попробуем решить проблему самостоятельно.
Отказ от ответственности
Работа проведена исключительно в образовательных целях, и ни в коем случае не является призывом к нарушению действующего законодательства. Автор не несёт никакой ответственности за незаконное использование представленных материалов.
Инструментарий
- IDA Pro — для дизассемблирования и исследования приложения
- Flat Assembler — для генерации необходимых машинных кодов
- Hexplorer — для внесения изменений в готовый исполняемый файл
- Resource Hacker — для изучения ресурсов
Исследование
Для определения количества свободных байт в оперативной памяти используется устаревшая функция GlobalMemoryStatus — именно её мы видим в таблице импорта «Звукозаписи». Поскольку эта функция используется в нескольких местах, более точно определить искомый участок кода нам поможет номер строки в ресурсах, выводимой при ошибке — это строка номер 6Eh.
Забавный факт — функция GlobalMemoryStatus в целях совместимости возвращает не более 2Гб свободной оперативной памяти независимо от того, сколько у вас свободно на самом деле. То есть старший бит числа свободных байт в любом случае не должен быть установлен в единицу, и число не должно интерпретироваться как отрицательное. Для того, чтобы найти проблему, нужно уяснить, что бывают различные типы условных переходов — для знаковых и беззнаковых данных.
![](https://habrastorage.org/getpro/habr/post_images/7c6/bde/8af/7c6bde8af11a729b319e5557650a3fdf.png)
Рассмотрим первое условие. Как видно, результат работы функции GlobalMemoryStatus сравнивается со значением, эквивалентным 1Мб. И не глядя на использование знакозависимой команды перехода
JGE
, данный код в свете ограничения результата GlobalMemoryStatus всегда работает верно. Проблема всплывает при проверке второго условия. Программа вычисляет сумму уже занятой записанным звуком памяти и свободной памяти (что установит старший бит числа), и сравнивает полученное число с количеством необходимых для выделения байт. Естественно, команда перехода для знаковых данных JLE
сработает некорректно, и для корректной работы её необходимо заменить командой JBE
(для беззнаковых данных). То есть наша задача сводится к замене одной команды.Патчинг
Физическое смещение интересующей нас команды: 6BD5h. Машинный код
JLE
— 7Eh. Чтобы получить машинный код команды JBE
скомпилируем в Flat Assembler следующий код:use32
jbe fake
fake:
Получим файл, в котором первым байтом будет код нужной команды — 76h. Осталось дело за малым — внести необходимые изменения в исполняемый файл. Для этого воспользуемся HEX редактором.Результат
sndrec32.zip (119Кб) — оригинальная и исправленная версии программы из английской Windows XP SP3.
Зачем это было нужно
Just for fun. Не стоит искать здесь никаких рационалистических побуждений. Существует масса других очень достойных и более удобных программ для записи и редактирования аудио. Просто сама возможность запустить и поработать в «той самой программе» греет душу :)