Проблема

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

Выходные данные, показанные на рис. 1, иллюстрируют трассировку. Моя программа начинает выполняться со строки 83. Адрес — 0x20XXXX будет местом загрузки моей программы. В современных системах Windows это будет отличаться, когда моя программа запускается из-за ASLR.

Отключение ASLR

Быстрое решение этой проблемы было бы таким: «Используйте Windows 7, ага». Однако я не думал, что это решение с расчетом на будущее, и просто отложил неизбежное, поэтому я решил посмотреть, смогу ли я сделать это на полностью пропатченной Windows 10.

Первым обращением было использование Google: «Windows 10 отключить alsr». К сожалению, ничего из этого не сработало. (К сожалению, раздел реестра «MoveImages», по-видимому, работает только в Windows 7.) Я пытался отключить Exploit Guard, но тоже безрезультатно.

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

Отключить ASLR в моей программе было достаточно просто, так как у меня был исходный код. Как только я перекомпилировал свою программу с параметрами компоновщика, как показано на рис. 2, средства просмотра PE, такие как CFF Explorer, сообщали о моей программе со следующими атрибутами:

Наконец, файл без поддержки ASLR не будет иметь таблицы перемещения.

Всё просто и хорошо. Здесь особо нечего сказать. Но как насчет DLL, которую загружала моя программа? Моя программа загружала DLL с закрытым исходным кодом, поэтому о ее перекомпиляции не могло быть и речи.

К счастью (сегодня нам так повезло!), CFF Explorer может редактировать PE-файлы (включая библиотеки DLL), поэтому я установил флаг IMAGE_FILE_RELOCS_STRIPPED и снял флаг IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE. Согласно спецификациям, показанным на рис. 6, это должно привести к тому, что моя DLL будет загружена в ее ImageBase (0x40000). Ранее я настроил свою программу на загрузку с адресом 0x20000, поэтому она не должна конфликтовать. Кроме того, в спецификациях также указано, что я получу сообщение об ошибке, если программа не сможет загрузить DLL в базу образа. Звучит здорово!

Тем не мение…

По какой-то причине 0x400000 был зарезервирован, и загрузчик вместо того, чтобы выдать ошибку, загрузил мою DLL в любое место по своему выбору. Это было удивительно, поскольку в спецификациях говорилось, что это вызовет ошибку. Однако такое поведение кажется ожидаемым, так как DLL имеет раздел .reloc в заголовке, поэтому загрузчик проигнорирует флаг и просто загрузит его.

Это означает, что мне нужно будет удалить раздел .reloc, а также, поскольку 0x400000 зарезервирован, я должен просто изменить DLL для загрузки по другому адресу. Эта операция называется ребазингом. Я мог бы также просто изменить его в CFF Explorer (или любом другом редакторе PE, но мне пришлось бы отредактировать несколько других полей), поэтому я поискал ленивый способ, и оказалось, что в Visual Studio есть как раз нужные инструменты для перезагрузка DLL!

Когда Visual Studio установлена, она создает 2 ярлыка для запуска командных строк, для которых настроены определенные пути. Эти подсказки позволяют пользователям использовать среду VS для компиляции, а также получать доступ к любым исполняемым файлам на пути к VS. В этом случае выбор 32-битной и 64-битной версии не имеет значения, и мы просто запускаем любую из них и запускаем editbin.

Команда, показанная на рис. 11, перебазирует нашу DLL с 0x400000 по умолчанию на 0x1f0000. Время проверить это в CFF Explorer!

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

Если вы удалите ссылку .reloc, DLL по-прежнему будет работать под x64dbg, но ее нельзя будет запустить в обычном режиме, так что, если возникнут конфликты адресов, программа выйдет из строя вместо того, чтобы счастливо загрузиться по какому-то случайному адресу, оставив меня займитесь устранением неполадок в будущем.

Конец?

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

Теперь вернемся к улучшению стабильности выполнения моей программы во время выполнения…