Жанр: Учеба

Главы книги о взломе

сторінка №2

ию типа:

s0.SetAt(0,s0[0]*(!RegFlag_1 ^ RegFlag_3));

Но кто может гарантировать, что нет четвертого или пятого флага? На
самом деле, число переменных класса ограничено и не так трудно
проанализировать их все. Кроме того, обычно флаги регистрации это
глобальные перемнные. Последних же в грамотно спроектированной программе на
объективно-ориентированном языке очень и очень немного.
Конечно, подобные технологии взлома построены на допущении ленивости
разработчиков защит. Тщательно продуманную защиту подобного типа
практически невозможно обнаружить даже при детальном анализе кода. Но,
такие случаи пока остаются экзотикой и часто не встречаются.
Блокирование элементов управленя не единстенно возможный вариант.
Многие демонстационные приложения при попытке выполения некоторой операции
(например, записи в файл) выдают диалоговое окно, информирующие об
отстутствии данной возможности в ограниченной версии. Иногда эта
возможность (вернее код, реализующий ее) действительно физически
отстутствует, но чаще он просто не получет управления.
Варианты блокировки больше рассматираться не будут, что бы избежать
повторения. Это слишком просто и элементарно ломается. Гораздо интереснее
искать пути выхода из ситуации, когда кода, реализующего данную операцию
по-просту нет. Конечно, чаще легче переписать программу полностью заново,
чем разобраться в взаимодействии с недостающим кодом, и воссоздать его.
Это столько сложная тема, что просто не может быть исчерпывающие
рассмотрена в рамках данной книги.
Рассмотрим достаточно простой пример подобной защиты: fiel:
//CD/SRC/CRACK10/Crack10.exe Это простой текствой редактор, который при
при попытке сохранения отредактированного файла выводит диалогове окно,
информирующие об отсутствии такой возможности в демо-версии.
Найдем этот вызов и дизассемблируем его:

.text:00401440

.text:00401440 push 0
.text:00401442 push 0
.text:00401444 push offset unk_0_404090
.text:00401449 call j_?AfxMessageBox@@YGHPBDII@Z
.text:0040144E xor eax, eax
.text:00401450 retn 4
.text:0040144E NagScreen endp
.text:0040144E

Допустим, можно удалить вызов j_?AfxMessageBox@@YGHPBDII@Z, но чего мы этим
добъемся? Однозначно, что код, обрабатывающий запись файла на диск
отсутствует. Впрочем, есть ненулевая вероятность, что он находится сразу
после retn или где-нибудь поблизости. Это происходит в случае использования
следующих конструкций:

BOOL CCRACK10Doc::OnSaveDocument(LPCTSTR lpszPathName)
{
AfxMessageBox("Это ограниченная версия. Пожалуйста, преобретайте полную");
return 0;
return CCRACK10Doc::OnSaveDocument(lpszPathName);
}

Однако, оптимизирующие компиляторы в таком случае просто удаляют
неиспользуемый код. Таким образом, вероятность, что сохранится код, не
получающий управления близка к нулю. Это здорово помогает разработчикам
защит, но печально для кракеров.
Впрочем, в нашей ситуации написать недостающий код легко. Мы можем
получить указатель на текствой буффер и просто сохранить его на диске. Все
это укладывается в десяток строк и может быть написано за несколько минут.
Передаваемые параметры можно узнать если установить на эту процедуру точку
останова и заглянуть отладчиком не вершину стека. Засланное в стек значение
очень похоже на указатель (а чем бы еще могло являться такое большое число?
) и в действительности является указателем на имя файла, что можно легко
проверить, взглянув на дамп памяти, расположенный по этом адресу.
Однако, гораздо большей проблеммой станет не написание своего кода, а
его внедрение в уже откомпилированный exe-файл. Под MS-DOS эта проблемма
уже была хорошо изучена, но Windows обесценила большую часть прошлого
опыта. Слишком велика оказалась разница между старой и новой платформами. С
другой стороны windows принесла и новые возможности такой модификации.
Например, помещение кода в DLL и простой вызов его оттуда. Подробное
рассмотрение таких примеров требует целой отдельной книги, поэтому
рассматриваемый здесь прием заведомо упрощен.

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

.rdata:00403644 dd offset j_?OnOpenDocument@CDocument
.rdata:00403648 dd offset sub_0_401440
^^^^^^^^^^^^^^^^^^^
.rdata:0040364C dd offset j_?OnCloseDocument@CDocument

Что предствавляют собой перечисленные смещения? Программисты, знакомые с
MFC, безошибочно узнают в них экземпляр класса CDocumnet. Это можно
подтвердить, если прокрутить экран немного вверх и перейдя по одной из двух
перекресных ссылок, посмотеть на следующий фрагмент:

401390 sub_0_401390 proc near
401390 push esi
401391 mov esi, ecx
401393 call j_??0CDocument@@QAE@XZ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
401398 mov dword ptr [esi], offset off_0_4035C8
40139E mov eax, esi
4013A0 pop esi
4013A1 retn
4013A1 sub_0_401390 endp

В таком случае становится ясно, что sub_0_401440 это виртуальная
функция CDocument::OnSavеDocument()! Но разработчик не передает
управления последней, а выводит диалогове окно и откразывается от записи.
А что если заменить sub_0_401440 на вызов функции по умолчанию
OnSaveDocument? Для этого сначала необходмио узнать импортируется ли
эта функция программой или нет. Воспользуемся для этой цели IDA и изучим
секцию rdata. К глубокому нашему сожалению OnSaveDocument в таблице импорта
отстутствует. Можно, конечно, вызвать любую функцию из DLL непосредственно,
загрузив ее LoadLibray. Это, конечно, потребует немалого места для
размещения нового кода в файле. Но благо, оно там с избытком имеется.
Компилятор выравнивает прологи всех функций по границе 0x10 байт для
оптимизации выполнения программы, поэтому остается много "дыр", которые
можно использовать взломщику для своих целей.
Это действительно очень просто, достаточно иметь минимальные навыки
программирования под windows. Однако, при первая же поптыка реализации
сталкиват с серьезной трудностью. Что бы вызвать функцию по адресу,
необходимо наличие GetProcAddress, а приложение не импортирует ее.
Печально на первый взгляд, но легко исправимо. Достаточно лишь слегка
изменить таблицу импорта, что бы включить недостающий вызов.
Обычно компияторы всегда оставлябт в файлах много пустого места, что бы
можно было немного расширть таблицу импорта. Что бы это сделать нужно знать
формат PE файла, который описан, например, в MSDN. Покажем на примере как
это можно сделать. Скопирум файл crack10.exe в myfile.exe Теперь запустим
HIEW 6.x (не ниже) и перейдем в секцию ипорта. В самом ее начале
расположен массив IMAGE_IMPORT_DESCRIPOR. Подробности о его структуре можно
подчерпнуть в SDK или MSDN. Двойное слово стоящее в начале это RVA
(relative virtual address) указатель на структуру IMAGE_THUNK_DATA. Вот
он-то нам и нужен. Преобразовать rva в локальное смещение внутри PE файла
можно сложив последний с image base, которую можно узнать из заголовка
файла.
Что собой предстваляет IMAGE_THUNK_DATA? Это массив указателей на
RVAFunctionName. Наглядно это предствавить можно если изучать это
структуру в любом подходящем для вас шестнадчатиричном редакторе,
например hiew. Что может быть интереснее, чем копание в PE файле вручную, а
не готовым инструментом просмотра. Конечно, последнее намного проще и даже
может быть приятнее, но не дает никаких полезных навыков. Хакер не должен
расчитывать на технику, а только на свои руки и голову. Кракер же может не
особо утруждаясь воспользоваться готовым редактором для таблиц
экспорта\импорта (например PEKPNXE Криса Касперски) и всего лишь
отредактировать одну строку, что не требует дополнительных объяснений.
Напротив же - ручаня работа с PE файлами пока еще не достаточно хорошо
описана и сам формат лишь отрывочно документирован. Едиинственным маяком в
мире WINDOWS был и остается заголовчный файл WINNT.H, который содержит все
необходимые нам структуры, но, увы, не содержит комментариев к ним.
Поэтому назначение некоторых полей придется выяснить самостоятельно.
Для начала загрузим исследуемый файл в hiew. Можно было бы сразу, вызвать
секцию импорта, но первый раз попытаемся для интереса найти ее вручную.
Заголовк PE файла начинается не сначала файла. Вместо этого там
расположена DOS-овская заглушка, которая нам совсем не интересна. Сам же PE
файл начинается с одноименной сингатуры. Двенадцатое (считая от нуля)
двойное слово это image base, который нам потребуется для вычислений,
связанных с RVA, в нашем случае равен 0x400000, что типично для win32
файлов.

Теперь нам необходимо найти адрес таблицы импорта . Он будет вторый в
директории (первый таблица экспорта). Под директорией здесь понимается
структура, расположенная в конце OPTIONAL HEADERа и содержащая необходиую
нам информацю. Я не привожу точного описания ее формата, отсылая читателя к
MSDN и wintnt.h Все же это книга не предназначена для пересказа
существующей документации и бессмыслено бы было тратить на это десятки
страниц. Попутно замечу, что на страдии подготовки книги это вызвало
некотрое возражение у тех людей, которые не владели английским даже на
уровне чтения технических текстов со словарем и не позаботились приобрести
даже электонной документации, которая свободно поставляется в любм
компилятором и даже доступна в Интернете на сайтах производителей и в первю
очередь, MicroSoft. Ну что на это можно сказать? Тогда не покупайте эту
книгу, а лазерный диск с сотнями тысяч готовых "краков" - очевидная
экономия времени и денег.
Итак, предположим, что мы уже выяснили, что таблица импорта
располагаетется по адресу 0x40000+0x3A90=0x43a90. Перейдем к ее
расмотрению, а точнее к рассмотрению IMAGE_THUNK_DATA, которое мы уже
затронули выше. Формат его данных очевиден из содержания:

.00403E30: F6 3E 00 00-02 3F 00 00-16 3F 00 00-C6 3E 00 00
.00403E40: E6 3E 00 00-26 3F 00 00-44 3F 00 00-BE 3E 00 00
.00403E50: 6A 3F 00 00-A8 3E 00 00-9A 3E 00 00-86 3E 00 00
.00403E60: 36 3F 00 00-56 3F 00 00-D8 3F 00 00-00 00 00 00

Поразмышляв над ним минутку-другую можно догаться, что его элемнты -
двойные слова - это RVA указатели. На эту мысль наталкивает самое значение,
например 0x3EF6 - находится в недалеко от текущей позиции, глубоко в
таблице импорта. Кроме того, все близкие к друг другу и однонаправленно
возорастающие значения элементов очень похожи на типичный массив
указателей.
Загляную в документацию, мы можем убедиться с правильности нашей
догадки. Попытаеся теперь, не образаясь к документации, угадать это
указатели НО ЧТО? Логично предположить, что вероятно, на
непосредственно имортируемые функции. Все еще не обращаясь к документации
перейдем по одному из указателей:

0403F00: 6D 00 83 00-5F 5F 73 65-74 75 73 65-72 6D 61 74 m Г __setusermat
^
0403F10: 68 65 72 72-00 00 9D 00-5F 61 64 6A-75 73 74 5F herr Э _adjust_
0403F20: 66 64 69 76-00 00 6A 00-5F 5F 70 5F-5F 63 6F 6D fdiv j __p__com
0403F30: 6D 6F 64 65-00 00 6F 00-5F 5F 70 5F-5F 66 6D 6F mode o __p__fmo

Это действительно имена функций, а слово стоящее перед ними, очевидно,
ординал! Однако, мы едва не упустили одну важную деталь - ведь существуют
функции, которые экспортируются только по ординалу и символьная информация
по просту не доступна. Не ужели тогда ДВОЙНЫЕ СЛОВА - указатели будут
расточительно указывать на СЛОВА ординалы? Разумеется нет, фирма MicroSoft
в стремлении к оптимизации предусмотрела такой вариант. В этом случаи все
элементы IMAGE_THUNK_DATA предстваляют собой не указатели, а
непосредственно ординалы функций. Что бы загрузчик мог распознать такую
ситуацию старший бит двойного слова равен единице. В результате, получается
массив наподобии следующего:

.00403B00: B2 10 00 80-86 11 00 80-FA 09 00 80-D0 09 00 80
.00403B10: 63 16 00 80-52 0F 00 80-41 04 00 80-4F 14 00 80
.00403B20: 5C 09 00 80-12 0D 00 80-B4 14 00 80-B6 14 00 80
.00403B30: A5 0A 00 80-EF 0F 00 80-5A 12 00 80-BB 14 00 80
.00403B40: A9 14 00 80-52 16 00 80-A6 0B 00 80-4B 0C 00 80

Любопытно, что в оптимизации WINDOWS NT MicroSoft опередила сама себя и
в системеных модулях все элементы выщеуказанного массива даже не ординалы,
а непосредственные смещения импортируемых функций. Это блестящее решение
MicroSoft заслуживает неприменного уважения. Действительно, загрузчкику
почти совсем не остается работы, что экономит не одну сотню тактов
процессора. И лишний раз подтвержает, что "решение от MicroSoft" чаще все
же ирония, чем горькая правда. И хотя windows в целом оставляем мрачное
впечателение, в ее недрах спрятано не мало интересных "конфеток". И в само
деле - ведь над ней работали весьма не глупые люди.
Четкое понимание структуры таблицы импорта необходимо для серьезных
манипуляций связанных с перемещением и добавлением новых элементов в
последнюю. Действительно, импортировать еще одну функцию очень просто.
Достаточно прописать ее ординал (или имя) в таблицу. Общее число элементов
нигде не учитывается, а конец таблицы же определятся завершающим нулем.
Взглянем на наш файл. RVA адрес первой структуры IMAGE_THUNK_DATA
равен 0x3B00. Учитывая, что image base 0x400000, получаем локальное
смещение 0x403B00. Как узнать из какого модуля импортируются эти функции?

Для этого заглянем в поле Name IMAGE_IMPORT_DESCRIPTOR, (четвертое двойное
слово от начала). В нашем случае оно указывает на стоку 'MFC42.DLL' Именно
в эту таблицу мы и должны добавить запись для OnSaveDocument. Разумеется,
что в таблице не будет свободного места и за ее концом находится начало
следующей. Кажется ситуация неразрешимая, однако давайте подумаем. На
каждую IMAGE_THUNK_DATA указывает всего одна ссылка. А что будет если мы
переместим одну из них в другое свободное место (которое навярняка
найдется) и в освободившеся простанство внесем новую запись?
Очевидно, что нам нужно освободить место в конце таблицы. В нашем
случае так находится небольшой массив из нескольких элементов. Очевидно,
это везение, инчаче бы пришлось перемещать и менять местами гораздо больше
массивов, что не было бы так наглядно.
Благодаря выравниванию адресов на границе секций данных и ресурсов
практически всегда есть бездна никем не занятого пространства.
Переместим выделенную структуру, например, по адресу 0х404110. Для этого
нужно скопировать блок с адреса 0х403E24 по 0х403E6B и записать его на
новое место. Теперь освободившеся место можно использовать по своему
усмотрению. Но прежде неоходимо сокрректировать ссылку на перемещенный
фрагмент. Для этого найдем в IMAGE_IMPORT_DESCRIPTOR прежний RVA адрес и
испрравим его на новый.
Запустим файл, что бы убедиться, что мы все сделали правильно и он
работает. Приступим к ручному импортированию функции из файла. Это
достаточно утомительный, но познавательный процесс, вынуждающий заглянуть
"под капот" PE файла, и понять как он загружается и работает. Для начала
изучим массив имортирумых функций:

.00403B00: B2 10 00 80-86 11 00 80-FA 09 00 80-D0 09 00 80
^^ ^^ ^^ ^^
.00403B10: 63 16 00 80-52 0F 00 80-41 04 00 80-4F 14 00 80
.00403B20: 5C 09 00 80-12 0D 00 80-B4 14 00 80-B6 14 00 80
.00403B30: A5 0A 00 80-EF 0F 00 80-5A 12 00 80-BB 14 00 80
.00403B40: A9 14 00 80-52 16 00 80-A6 0B 00 80-4B 0C 00 80

Видно, что все они импортируются по ординалу. И нам необходимо только
добавить еще один. Находим в файле MFC42.map функцию OnSaveDocument и на
основе полученного смещения определяем ординал с помошью dumpbin или любой
другой аналогичной утилиты получаем, что ее ординал 0x1359. Дописываем ее в
конец таблицы. Запускаем dumpbin, что бы удостовериться, что он заметил
проделанные изменения. Однако, это далеко не конец нашей работы, а скорее
ее только начало. Что нам даст новая запись в IMAGE_THUK_DATA? Честно
говоря ничего. Нам нужно узанть адрес функции после загрузки, а как это
сделать? Для этого сущестует еще одно поле в IMAGE_IMPORT_DESCRIPTOR -
это пятое двойное слово, указывающие адрес массива, в каждый элемент
которого загрузчик операционной системы запишет реальный адрес
импортируемой функции. В нашем случае для MFC42.DLL такая структура
расположена по адресу 0x40300C. Рассмотрим ее поближе, но сначала обратим
внимание, что адрес 0x40300C находится за пределами секции импорта и
уже пренадлежит секции .rdata Это обстоятельство на самом деле очень важно,
т.к. иначе бы загрузчик просто бы не смог получить доступа к памяти на
запись, а следовательно изменить значение. Поэтому эта таблица перемещаема
только в пределах .rdata Но что она собой представляет? Гораздо проще и
быстрее выяснить это самостоятельно, чем искать в докуменации среди
множества бесполезной для нас сейчас информации. Рассмотрие ее поближе:

.00403000: 8C 3F 00 00-78 3F 00 00-00 00 00 00-B2 10 00 80
^^
.00403010: 86 11 00 80-FA 09 00 80-D0 09 00 80-63 16 00 80
.00403020: 52 0F 00 80-41 04 00 80-4F 14 00 80-5C 09 00 80
.00403030: 12 0D 00 80-B4 14 00 80-B6 14 00 80-A5 0A 00 80
.00403040: EF 0F 00 80-5A 12 00 80-BB 14 00 80-A9 14 00 80

Не правда ли эти таблицы идентичны? И та и другая перечисляет ординалы.
Однако существенная разница между ними все же есть. Первая сохраняется
неизменной на всем протяжении работы, а последняя замещается реальными
адречами импортируемых функций уже на стадии загрузки. И именно ее
приложение использует для вызовов типа CALL DWORD PTR [0x403010].
Очевидно, что в случае ипорта по имени все элементы таблицы будут
указателями на ASCIIZ-строки с именем и ординалом функции. Заглянув в
MSDN можно с гордостью констатировать тот факт, что мы ни где не ошиблись в
наших предположениях. Со временем большинство исследователей недр windows
все реже и реже заглядывают в документацию, поскольку многое и так
достаточно очевидно и нет никаой нужды в разъяснении.
Печально, что служит примером для подражания начинающих и неопытных
хакеров, которые воспринимают это как повод для отказа от документации
вообще. И в результате тычустся в слепую или начинают задавать глупые
вопоосы наподобии "какой функцией windows открывет файл. Я установил на
OpenFile точку останова, а она не сработала. Почему?" Действительно общий
объем докуменатции для разработчика win32 такой, что даже беглый просмотр
заголовков отнимет не один месяц времени. Это все так. Еще под window 3.1
говорили, что нужно не меньше года обучения, что бы стать полноценным
программистом под эту платформу. Насколько же все усложнилось с тех пор!

Самое обидное, что на этом фоне делается основной упор на каркасные
библиотеки типа MFC, технологии OLE и ActiveX и системному программированию
просто не остается место - ни в умах разработчиков не в документации.
Лозунг - все что Вас нужно уже сделано компанией MicroSoft в самом деле
сейчас очень популярен, но многих людей (включая и меня) он приводит в
ярость. Программисты старого поколения до сих пор любят все делать своими
руками и не передаю выполнения своей программы чужому коду, пока не изучат
последний.
Полноценным системщиком можно стать лишь отказавшить от MFC и C++,
а попробовать написать несколько серьезных приложений на старом добром Си.
Даже не ассемблере, а простом выскоуровневом языке. Непосредственное
общение с win32 может с первого взгляда показаться пугающим, но это
единственно возможный вариант почуствовать архитектуру системы.Без этого
говорить о хакерстве просто смешно.
Однако мы ушли далеко всторону. Но не будем возрашаться назад.
Признаюсь, я вас обманул и завел в тупиковый путь. Надеюсь, что осознание
это факта уже дошло до читателя. В самом деле, что бы добавить еще одну
запись в вышеуказанную секцию надо ее чуточку разжвинуть и... получиь GPF.
В самом деле, на нее указыает множество ссыклок из разных частей кода.
Изменить из все не предствавляется возможным, особенно там, где
использовалась косвенная адресация.
Впрочем, если быть до конца честным, в большинство компиляторов
генерируют хорошо всем известные:

.004018D0: FF25C4314000 jmp MFC42.4612
.004018D6: FF2590314000 jmp MFC42.4610
.004018DC: FF2594314000 jmp MFC42.6375
.004018E2: FF2510304000 jmp MFC42.4486
.004018E8: FF2514304000 jmp MFC42.2554
.004018EE: FF2518304000 jmp MFC42.2512
.004018F4: FF251C304000 jmp MFC42.5731
.004018FA: FF2520304000 jmp MFC42.3922
.00401900: FF2524304000 jmp MFC42.1089

Таким образом, на каждый элемент имеется всего одна ссылка, которая к
тому же легко может быть найдена и скоректирована. Выходит, я дважды
обманул читателя. На самом деле это не тупик, а просто хлопотный, но
очевидный, путь. Я встречал многих хакеров, которе соблазнились отпавиться
по нему и для коррекции ссылко даже писали специальную программу или скипт
к IDA.
Однако, можно пойти более короткой дорогой. Кто нас заставляет
добавлять элемнт в существующую таблицу, когда можно создать свою и
разместить ее где угодно! Это в самом деле очень просто.
Поскольку сразу за концом IMAGE_IMPORT_DESCRIPOR следует
IMAGE_THUNK_DATA, то очевидно, что добавить еще одну запись, можно только
переместив одну из двух на свободное место. Первая несравненно короче,
поэтому и шансов найти бесхозного пространства для нее побольше. Строго
говоря нам необходимо разместить ее в пределах таблицы импорта и никто не
разрешит ее перемещать с секцию .data - получится перекрывание секций, и
последсивия не застаят себя ждать... hiew "заругается" на такой файл. И,
пожалуй, все. Действительно, если изучить код загрузчика windows становится
ясно, что ему глубоко все равно в какой секции расположена таблица импорта
и более того, совершенно безразличен размер последней, а точнее его
соответствие с реальным. Конец определяется null-записью.
На самом деле, необходимо отдавать себе отчет в зыбкости таких
рассуждений. Никто не гарантирует, что в будущем MicroSoft не перепишет
загрузчик, который будет делать такие проверки или не появится прикладных
программ (в частоности антивирусов) которые не контролировали бы
корректность заголовка.
С другой стороны, работа хакера почти всегда базируется на отклонении
от документации и рекомендаций сопутствующих к ней руководств. В противном
же случае ничего не остается, как сидеть бездействовать или
перекомпилировать полученный ассемблером и исравленный текст в исполняемый
файл, что сопряжено с многочисленными проблеммами и трудозатратами.
Скопируем IMAGE_IMPORT_DESCRIPOR в любое свободное место секции данных
и изменим на нее ссылку в Import Directory. Теперь нам необходимо создать
новую запись в ней. Начнем с четвертого двойного слова, указывающего на имя
функции. Можно состлаться на уже существующую строку 'MFC42.DLL', а можно
созадть свою и указать на нее. Последнее нам дает больше свободы и
независимости. Поэтому поступим именно так:

.004041D0: 4D 46 43 34-32 2E 44 4C-4C 00 00 00-00 00 00 00 MFC42.DLL

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


.004041E0: 59 13 00 80-00 00 00 00-00 00 00 00-00 00 00 00 Y. А

Понятно, что 0x1359 это и есть ипортируемая функция OnSaveDocument, а
старший бит 0x8000 указывает, что последняя ипортируется по ординулу.
Остается создать таблицу адресов, точнее таблицу создавать нет никакой
необходимости. Не смотря на то, что каждый ее элемент по теории должен
ссылаться на соотвествующую фукцию, оптимизация загрузчка привела к тому,
что он никак не использует начальные значения таблицы адресов, а вносит
записи в том порядке, в котором они перечислены в таблице имен
(IMAGE_THUNK_DATA). Поэтому достаточно лишь найти незанятое пространство и
установить на него указатель в последнем поле IMAGE_IMPORT_DESCRIPOR.
Однако, тут мы наталкиваемся на серьезные ограниченя. Загрузчику на
запись доступна только .rdata, в которой так скажем свободным местом не
густо. Более того, ни один элемент нельзя перемещать, поскольку ссылки на
него разбросаны по всему коду программы. Остается только надесятся, что в
результате выравнивания в конце таблицы найдется немножко пространства для
наших целей. И действительно, несколько десятков байт свободно. Для нас это
более, че

Список сторінок

Поділитися у соцмережах

☏ Замовлення реклами: +3805044-68-872

© Асоціація електронних бібліотек України

☝ Усі матеріали сайту (зокрема статті, зображення, рекламні оголошення тощо) призначені лише для попереднього ознайомлення. Усі права на публікації, представлені на сайті, належать їхнім законним власникам. Просимо Вас не зберігати копії інформації.