Добрый день, воины дзена! Я особо никогда не занимался работй по профилю этого форума, но жинь заставляет. Я прошу прощения, что не разместил свой первый "профильный" вопрос в тему для новичков, т.к. я надеюсь, что он достоин этого раздела (если мне "старшие товарищи" скажут, чо это не так - я извинюсь). Я хочу поправить dll. Хочу заменить функцию недающую нормально работать приложению на "хорошую" функцию. Вообще-то "плохих" функций несколько, но всех их я могу просто "обойти" или меняя j** на jmp сделать их "плохую" роботу бессмысленной. Эта же функция - делает кроме "плохой" работы много полезного. И я ее должен не править, а пактически написать заново. т.к. моя функция оказалась больше оригинальной я решил использовать для размещения "правильной" функции тело большой "плохой" уже никогда неиспользуемой функции. 1.Я за-nop-ил (чтобы освободить место для "правильной") из нее все кроме: push ebp mov ebp, esp push ebp add esp, 0FFFFFFF8 , выделяющие локальную память в начале и: mov al, 1 mov esp, ebp pop ebp retn,строк выравнивающих память и возврат 1 из функции в конце. 2.Передал управление на эту пустую "болванку"... и был очень неприятно удивлен. Я зпускал и выключал форму и получал случайным образом то ошибку - 'Privileged instruction'; то ошибку - 'Acsess violation at address XXXXXXXX in odule 'my.dll' причем XXXXXXXX - адрес внутри "болванки"; - пару раз вызов "болванки" прошел нормально (как я ожидал). 3. В конце концов я идентифицировал "проблемные" инструкции которые "нельзя" удалять. Вот примеры: .text:0040BB4A 8B058B104B00 mov eax, _dword_4B108B_Const_000000AF или .text:0040BBB8 FF15E4774B00 call _dword_4B77E4_OtherDLLFuncNamePoint или .text:0040BB5C 833D80104B00FF cmp _dword_4B1080_Handler, 0FFFFFFFFh (причем последняя легко патчиться, например, на .text:0040BB5C 8B0580104B00 mov eax, _dword_4B1080_Handler [а эта инструкция нужна мне в "хорошей" функции]. т.е главное чтобы адресс 4B1080 - оставался на том-же месте). Всех их объединяет одно - они обращаються "очень далеко" от исполняемого кода. Если я оставляю эти инструции - все OK (В том смысле, что ошибок нет). 4.Попытки вызвать инструкцию .text:0040BB5C 8B0580104B00 mov eax, _dword_4B1080_Handler [для "хорошей" функции] в удбном для меня месте приводит к ошибке: 'Acsess violation at address XXXXXXXX in odule 'my.dll'. Read 4B1080'. причем XXXXXXXX - удобный для меня адрес по которому размещен вызов; 5. Я понял, что в моем понимании фразы "пропатчить функцию" есть серъезные пробелы и я решил написать на WASM.RU. Собственно вопрос: Что я должен понять, чтобы вычистить свою "болванку" от "проблемных" инструкций и затем использовать их же в свом патче? Если вопрос ламерский - прошу сделать снисхождение, т.к. за свое невежество я уже наказан потерей времени - 2 дня посто "полягло". Кажеться вот оно решение вот..вот и затягивает - невозможно оторваться - хуже футбола.
Т.е. при передачи управления на Код (Text): push ebp mov ebp, esp push ebp add esp, 0FFFFFFF8 nop nop mov al, 1 mov esp, ebp pop ebp retn вылетает Acsess violation? Быть такого не должно здесь обращений к памяти нет, кроме как к стеку. Наверное нопы не туда вставляются. под отладчиком смотрел? Что-то моло чего понял дальше. Если переписывать участок кода на новое место, то переписываемый код должен быть базонезависимым. Он базонезависим?
Код не есть базонезависимым, но полтора десятка смещений в коде (функция небольшая - до 300 байт) я откорректировал. Но результат - как с пустой болванкой (в смысле те же проблемы) push ebp mov ebp, esp push ebp add esp, 0FFFFFFF8 nop nop mov al, 1 mov esp, ebp pop ebp retn В том то и дело что именно так!!! Причем j** на jmp меняй не хочу, а эти участки с text:0040BB4A 8B058B104B00 mov eax, _dword_4B108B_Const_000000AF как заколдованные - тронишь или переместишь на байт - Acsess violation. Причем сам код text:0040BB4A 8B058B104B00 mov eax, _dword_4B108B_Const_000000AF абсолютно базо-независимый
Надо ещё релоки править (Чем можно отредактировать релоки в DLL?) или попробуй свой exe'шник перелинковать на другой imagebase (0x00600000 к примеру)
snpik Эти инструкции как раз базозависимые! Поэтому их частично перезаписывают релоки. "Проблемные" инструкции лучше всего "обходить", вставляя короткий безусловный jmp перед ними, который ведёт на следующий после проблемной инттрукции адрес: Код (Text): jmp after_bad_instruction some_bad_instruction after_bad_instruction: ЗЫ: bogrus быстрее печатает
snpik Передал управление на эту пустую "болванку"... и был очень В тело твоей пустой болванки попали релоки...
Большое спасибо asd, bogrus, Quantum и crypto за участие!!! Понятно.Ключевое слово "релоки". 1. Делаю поиск и нахожу следующие: ---------------------------------------------------------------------- ------- Базовая поправка - это настройка по отношению к инструкции или значению инициализированной переменной; ЕХЕ-файлы или DLL нуждаются в такой поправке, если загрузчик не может загрузить файл по адресу, который предполагался компоновщиком. Если загрузчику удается загрузить отображение по указанному компоновщиком базовому адресу, загрузчик игнорирует поправочную информацию в этой секции. Если вам хочется попытать счастья и вы надеетесь, что загрузчик всегда сможет загрузить отображение по указанному компоновщиком базовому адресу, используйте ключ /FIXED. (На этом месте я вспоминаю, что при некоторых запусках у меня проблем небыло) Поправки обычно требуются только для инструкций, использующих 32-разрядные смещения для данных. (На этом месте я вспоминаю, что мои "проблемные" инструкции имеют такую же структуру.) ---------------------------------------------------------------------- ------- Симптомы моей dll получают объяснение в свете прочитанного. 2. Запускаю PETools.exe и скармливаю свою dll RelocRebuilder.dll - плагину PETools.exe dll увеличелась на килобайт 20. (Поруччик Кржевский, как Вам удается так легко сближаться с женщинами? - спрашивает молодой корнет. Знаете ли, корнет, я подхожу к даме и спрашиваю: "Мадам, можно Вас запердолить?" - Фу, поруччик, так можно же по морде... - Можно по морде, а можно и запердолить...) Получаем по морде - dll не запускаеться. 3. Запускаю PETools.exe снова и через меню Tools -> PE Editor гружу свою dll, жму "Sections" и вижу секцию .reloc с кучей адресов. Смотрю в HEX - редакторе все адреса в файле в надежде найти что нибудь осмысленное и вроде бы нахожу. Raw offset - это адрес в файле dll. Секция .reloc занимает весь огромный хвост dll. В этом я убеждаюсь окончательно когда жму PETools.exe "Directories" -> "Base Relocation Table". По адресу .reloc -> Raw offset из "Sections" я вижу RVA (4 bytes) и Size of Block (4 bytes) . В секции Items, как я понял, находиться количество элементов в блоке. Размер блока (в Word) за вычетом 4 word на описание RVA и Size of Block совпадает с Items. То есть 1 Item описываеться двумя байтами. Но что это за такие Items??? 4. Позицианирую курсор на одном из блоков в "Directories" -> "Base Relocation Table". В окне Block Items появляються эти самые Items. Каждая Items имеет порядковый номер, два адреса (RVA и offset), отличающихся на одно число и параметр Type, который у меня один и тотже (помоему это вторй байт описывающий Item и равный везде $30). Открываю Ida беру RVA добавляя к нему $400 000 и вижу исполняемый код. Получившийся адрес указывает на средину инструкции. Беру другой RVA (другой Item), опять добавляю $400 000 и я опять в средине инструкции. По инерции делаю тоже еще пару раз. Результат тот-же: Я в средине инструкции. Е ма е - так это же как раз те "проблемные" инструкции, и только они. А внутри их я именно в том месте, где в инструкции начинаеться четырехбайтное смещение, которое я еще вчера считал абсолютным. Понятно теперь, что это за Items! 4.Отрезаю всю секцию .reloc от dll, Запускаю PETools.exe и скармливаю свою dll RelocRebuilder.dll - плагину PETools.exe Acsess Violation на этапе работы RelocRebuilder.dll. Ладно по морде так по морде. 5. Так, что я могу сделать руками: а)Определить границы своей функции, и идентифицировать Block (Blocks) из секции .reloc к которому (которым) пренадлежат эти границы. б)Посчитать количество уже описанных Items для старой функции. в)Посчитать количество инструкций с 32-разрядным смещением для "правильной" функции. (конечно лучше, чтобы они не отличались) г)на разницу чисел полученых в п. б) и в) скорректировать: - рамер dll. - Константу Size of Block (Size of Blocks). В результате мы должны получить Block (Blocks) с новым (скорректированным) количеством Items (местом для Items). д)Откорректировать Items (правя смещения Item от RVA Block-а). 6)Собственно вопрос: а) ПОЛНОСТЬЮ ЛИ отражает п.5. идею фразы "править релоки", или я что-то опять упустил??? б)Вопрос косвенно относящийся к предмету разговора. Я dll с "правильной" функцией и правлеными смещениями, но без исправленых релоков отдал Иде 4.9. строка кода которая ссылается на локальную переменную var_9 (смещение -9 от ebp, и по моему пониманию, обязанная выглядеть приблизительно как: 0040BC3B 8B45F7 mov eax, [ebp+var_9] при последнем обращении к ней (в конце "правильной" функции) выглядит как: 0040BC3B 8B45F7 mov eax, [ebp-9] [причем -9 на красном фоне]. до этого с пол десятка обращений к этой локальной переменной транслировалось ожидаемым образом ([ebp+var_9]). Это просто моя ошибка или следствие несбалансированности dll с секцией .reloc?? И если это моя ошибка то что может вызывать ее?? (Самому в голову пока ничего не идет). Заранее большое спасибо.
Я dll с "правильной" функцией и правлеными смещениями но без исправленых релоков отдал Иде 4.9 Ты файл просто перегрузил? Тогда можно удалить код (U), а потом его снова создать (C).
Убил буквой "U" две инструкции с обращением к var_9 1. 0040BC3B 8B45F7 mov eax, [ebp+var_9] ; 2. 0040BC4B 8B45F7 mov eax, [ebp-9] Нажал "С" обе стали выглядеть как mov eax, [ebp-9], но во второй как был красный фон под 9, так и остался, а первая, где было [ebp+var_9] до "U" - c нормальным белым фоном. Ida чует какую-то непонятку. Что - то мне кажеться, что тут только практика нужна. Просто хочеться быть уверенным, что я правильно понял как "править релоки" перед практикой. Потому как воспользоватся советом Quantuma (спасибо за совет, конечно) с jmp after_bad_instruction some_bad_instruction after_bad_instruction: не светит. У меня у самого (в "хорошей" функции) полно таких "проблемных инструкций", причем с такой плотностью, что их ни как не наложишь на те, что были до чистки.
С релоками никогда не общался. Сейчас прочитал, возникли следующие сомнения и предложения: 1.snpik Я вот думаю, если случится такая ситуация, что исправляемый блок релоков не последний? Тогда, как будут обрабатываться последующие блоки, ведь за концом исправленного блока останется мусор от старых релоков. Наверное следует сдвинуть последующие блоки релоков на количество убранных элементов? Проще всего мне представляется убить старые релоки, которые портят новую функцию, а свои релоки пропатчить самому. Всё это имхо, так как не пробовал. P.s. А dll большая?
snpik да, $3'ка это IMAGE_REL_BASED_HIGHLOW, тебе необходимо найти для своих проблемных инструкций соотв. Item'ы и изменить $3-ку на $0 (IMAGE_REL_BASED_ABSOLUTE), тогда загрузчик должен их пропустить
snpik В самом начале была такая "проблемная" инструкция: Код (Text): .text:0040BB4A 8B058B104B00 mov eax, _dword_4B108B_Const_000000AF Если слегка исправить 2 первых байта: Код (Text): [b]90[/b] nop [b]BE[/b] 8B104B00 mov esi,4B108B Оригинальный релок при этом не пострадал! Зато в регистре esi (можно и любой другой заюзать) получаем фактически значение дельты от релока, которое можно использовать далее в функции как базу! Т.е. теперь вместо ds:[4B108C] можно писать [esi + 1] и т.д. Таким образом можно оставить первый релок как есть а все остальные прибить.
Quantum Это уже изощренный способ - можно тулзу попробовать такую реализовать, которая будет максимально использовать имеющиеся релоки и текст изменений. Хорошая курсовая работа...
LordPE может редактировать релоки. Правда он может еще некоторый мусор добавить в exe-шку. Например, при добавлении моего импорта, он написал [LordPE] где-то в начале файла. Еще добавил новую секцию под именем ".Silvana", но это ожидаемо. Кстати, если патчить надо много, можно подключить свою библиотеку - добавить импорт любой ее функции - и патчить все (или не все, а только те места, где нужен дополнительный код) в момент загрузки библиотеки. Я так и сделал с H3WMapEd.exe
Отчет о проделаной работе: Релоки удалось поправить вручную!!! В старой функции их оказалось на 1 больше. Я в общих чертах воспользовался советами Quantuma ("строить код так, чтобы с релоками было меньше мороки") чтобы не резать dll и не двигать блоки. Я оставил самую безобидную инструкцию из старой функции с ее оригинальным релоком. Остальные релоки поправил. Type менять необходимость отпала. Я с этим параметром и не игрался. Var_9 выбросил и обошелся без этой переменной. Что хотела Ida, раскрашивая смещение от ebp в красный цвет (за что спаибо Ide), так и не узнал. Пока думаю, что п.5 всетаки отражает идею фразы "править релоки". Есть, првда, уточнения: - надо еще менять параметр размера секции .reloc если таковой изменяеться. - да, и, конено, блоки после правки, должны идти один за другим без всяких щелей и налезаний блоков друг на друга; тут, я думаю, прав asd - это логично. Хотя изменение размера - не проверено. На данный момент "хорошая" функция ведет себя предсказуемо (хотя до конца протестировать ее работу смогу только в понедельник) т.е. без скндалов со стороны Windows (что и требовалось доказать в задаче), за что большое СПАСИБО всем услышавшим мои крики о помощи. GrayFace Кстати, если патчить надо много, можно подключить свою библиотеку - добавить импорт любой ее функции - и патчить все (или не все, а только те места, где нужен дополнительный код) в момент загрузки библиотеки. Кстати это хорошее альтернативное решение, особенно когда нет возможности сбалансировать релоки "старого" и "нового".