IPB

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> patсher_x86
Berserker
сообщение 08 Nov 2017, 16:38
Сообщение #21

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Цитата
На вог-форуме есть тема по патчеру, но, к сожалению, цель с которой я эту тему там создавал - не достигнута.

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

Имеется сейчас актуальный pas-файл для подключения патчера и ссылка на сам патчер последней версии?


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
baratorch
сообщение 09 Nov 2017, 22:23
Сообщение #22

Immortal
Сообщений: 2 373
Спасибо сказали: 4534 раза




в патчере в мосте лоу-хука до сих пор портянка команд на сохранение каждого регистра
Для все той же обратной совместимости.
Более того, в коде моста много данных в регистр/стек попадают через кучу (временные переменные).
сейчаc код моста вот такой:


Порядок регистров, адреса возврата и регистра флагов здесь продиктован лишь обратной совместимостью.
Да, можно изменив порядок этого всего внутри HookContex сделать короче и красивее.
Но мне лично лень ломать голову как это сделать
я не ASM-нинзя, здесь скорее кто-то вроде MasterOfPuppets нужен.
Предложите ваше решение и я добавлю в патчер "NewFastLoHook" хук. а старый LoHook останется для обратной совместимости.

Но вообще от этой страшной медленной портянки никто, кроме тебя не страдает.
Да и начиная с версии 4 используя PatcherInstance::WriteAsmHook или Patcher::WriteAsmCode можно легко написать низкоуровневый хук точно и тонко самому определив код его моста.


Цитата
Имеется сейчас актуальный pas-файл для подключения патчера и ссылка на сам патчер последней версии?

актуального pas-файла нет, так как он уже несколько лет (!) никому не нужен.
можно использовать старый, но, очевидно, не будет доступен добавленный позднее функционал (например Asm-патчи и Asm-хуки)

Здесь последний патчер версии 4.2.8, хэдер для C++ версии 4.2 и pas-файл версии 2.1:
скачать патчер SDK


--------------------
HoMM 3 HD:
http://sites.google.com/site/heroes3hd
последняя версия - 3.61f


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 10 Nov 2017, 23:33 (Сообщение отредактировал Berserker - 11 Nov 2017, 13:38)
Сообщение #23

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Спасибо, старого файла хватит вполне, сам добавлю при необходимости.

Самый простой переходник:
Код
pushad
push esp;
mov eax, [адрес обработчика]
call eax
test eax, eax // выполнять ли результат по умолчанию
jz skip_default
popad
add esp, 4
затёртые команды + nop
push адрес возврата
ret

skip_default:
popad
ret


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


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
baratorch
сообщение 11 Nov 2017, 16:13 (Сообщение отредактировал baratorch - 11 Nov 2017, 16:18)
Сообщение #24

Immortal
Сообщений: 2 373
Спасибо сказали: 4534 раза




озадачился я вопросом скорости выполнения моста
состряпал тест вот с таким кодом:




скачать тестовый экзешник

результат несколько неожиданный

на моем рабочем ноуте такой:
pushad... : 3074
push edi...: 2386
push eax...: 2590

на лобби сервере для Хоты:
pushad... : 6719
push edi...: 4547
push eax...: 4625

* можно посмотреть в отладчике что тест выполняется честно
* при перестановке местами вариантов результаты теста не меняются

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


***

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

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

вобщем теперь переживать из-за размера моста можно будет меньше.

кстати в дампе патчера есть записи
bridge memory - это память выделенная патчером под все мосты.
bridges sizes sum - это суммарный размер всех мостов.


--------------------
HoMM 3 HD:
http://sites.google.com/site/heroes3hd
последняя версия - 3.61f


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 11 Nov 2017, 16:18 (Сообщение отредактировал Berserker - 11 Nov 2017, 16:20)
Сообщение #25

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Привет, спасибо за тест smile2.gif. Удивлён несколько. Хотя в тесте и нет доступа к памяти в куче (.

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

(* Remove Erm trigger "BeforeSaveGame" call *)
Core.p.WriteDataPatch($7051F5, ['9090909090']);

Не использовались только переходники на LoHook. Гляну, можно ли безболезненно подменить одни вызовы другими. Если вызываемая функция получает один и тот же контекст в качестве аргумента, имеет соглашение stdcall, то должно сработать.


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
baratorch
сообщение 11 Nov 2017, 16:49
Сообщение #26

Immortal
Сообщений: 2 373
Спасибо сказали: 4534 раза




Цитата(Berserker)
Самый простой переходник:...

Ну ты привел код из эры. Я его итак видел.
Но твой код отличается по функционалу:
во-первых, твой код будет портить регистр флагов, а мой нет (причем у меня в хуке можно читать и менять флаги)
во-вторых с твоим мостом нельзя будет внутри хука делать push (на вог-форуме я уже писал об этом)
в-третьих я не очень понимаю как с твоим кодом внутри хука можно работать с адресом возврата.
у меня на мост посылает команда jmp, а у тебя чтоли call раз адрес возврата уже запушен до начала выполнения моста?
В любом случае если делать возможность полноценной работы с esp (push) внутри хука, то обойтись простыми push/pop с адресом возврата не получится.

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

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


--------------------
HoMM 3 HD:
http://sites.google.com/site/heroes3hd
последняя версия - 3.61f
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 11 Nov 2017, 18:08 (Сообщение отредактировал Berserker - 11 Nov 2017, 18:09)
Сообщение #27

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Странно, что я pushfd/popfd не добавил раньше. Если при заменах call-ов флаги априори и не должны сохраняться, то при перехвате обычных инструкций ещё как должны (.
Адрес возврата менялся через структуру контекста. Context.Ret := новое значение. А вот push-подобая работа со стеком за всё время, если честно, не пригодилась.

С отладочными картами работу закончил (возможность получить человекочитаемый адрес по PE-модулю + смещению вида "Era.3E86C (PoTweak.OnBeforeResetErmFunc in PoTweak.pas on line 117)"). Попробую сейчас перенаправить большую часть перехватов на patcher. Сообщу о проблемах, если будут smile2.gif

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


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 11 Nov 2017, 18:57 (Сообщение отредактировал Berserker - 11 Nov 2017, 18:57)
Сообщение #28

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Пока что вылеты. Я так понимаю, как LoHook нет метода, возвращающего адрес в рамках моста для вызова оригинальной (замещённой функции) или оригинальных команд с последующим продолжением исполнения, как если бы патча не существовало?.
У меня эти несколько лет Data-патчи уже используют патчер, равно как в достаточно HiHook вызовов. По вылетам смотрю, пока не ясно.


Лог выше не актуален, ниже использую уже THookContext патчера.

Вот явно кусок патча в куче:
https://yadi.sk/i/KGgPuvxG3Pc9LY
Но возвращает он по адресу в куче куда-то не туда:
https://yadi.sk/i/5vAcbI2y3Pc9Pk

Что я сделал: THookContext сделал синонимом PatchApi.THookContext + подправил ApiHook:

Код
function ApiHook (HandlerAddr: pointer; HookType: integer; CodeAddr: pointer): {n} pointer;
begin
  if HookType = HOOKTYPE_BRIDGE then begin
    p.WriteLoHook(CodeAddr, HandlerAddr);
  end else begin
    result := Hook(HandlerAddr, HookType, CalcHookSize(CodeAddr), CodeAddr);
  end;
end; // .function ApiHook


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 11 Nov 2017, 19:19 (Сообщение отредактировал Berserker - 11 Nov 2017, 20:25)
Сообщение #29

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Поскольку у Эры с плагинами тоже вопрос обратной бинарной совместимости, сохранение флагов и манипулирование стеком не нужны, то предлагаю в перспективе добавить в патчер отдельный метод WriteEraBridgeHook или что-то в этом роде, который будет иметь идентичный функционал + возвращать адрес кода по умолчанию (который в мосте, то бишь в куче = затёртые команды).
Остальное на 90% и так использует патчер.

Но спешить не стоит. Как раз думаю дать возможность функциям установки заплаток связывать заплатки с пользовательским dword. Тогда обработчик (callback) становится делегатом или замыканием, описываемым парой: адрес + указатель на данные.

В любом случае в следующем обновлении Эры я включу последнюю версию патчера. На ней уже и работаю.


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
baratorch
сообщение 11 Nov 2017, 21:01 (Сообщение отредактировал baratorch - 11 Nov 2017, 21:24)
Сообщение #30

Immortal
Сообщений: 2 373
Спасибо сказали: 4534 раза




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

Я что-то не понял вопроса.
Всмысле можно ли поставить LoHook который ничего не делает (просто выполняет затертый код)?
Да, можно:
Код
int __stdcall NopFunc(LoHook* h, HookContext* c)
{
return EXEC_DEFAULT;
}
...
_PI->WriteLoHook(0xAABBCC, NopFunc);

или нужно что-то вроде:
Код
int __stdcall Handler(LoHook* h, HookContext* c)
{
какой-то код...
...
выполнить затертое
...
какой-то код...
}

если да, то такое нельзя сделать.
такое есть в WriteAsmHook:
_PI->WriteAsmHook("какие-то команды....; _ExecDefault; какие-то команды...", 0);

Цитата
LoHook нет метода, возвращающего адрес в рамках моста для вызова оригинальной (замещённой функции)

для LoHook нет понятия оригинальной (замещенной) функции.
LoHook устанавливается просто на код. Что там за код под ним - не имеет значения.

Я из кода эры не очень могу понять как устанавливается HOOKTYPE_BRIDGE хук.
В самом мосте адрес возврата у тебя не пушится.
Но в контексте он есть, так?
Значит от попадает в стек до выполнения моста, так?
Значит перенаправление на сам мост из оригинального кода идет посредством call?


У меня же перенаправление на мост идет посредством jmp
а адрес возврата помещается в контекст внутри моста.

Второе. Я правильно понимаю что в твоем HOOKTYPE_BRIDGE мосте, если Handler возвращает EXEC_DEFAULT,
то мост игнорирует адрес возврата из контекста и прыгает обратно туда, куда должен по умолчанию?

У меня же в мост прыгает по адресу возврата из контекста , который мы возможно изменили внутри Handler, в любом случае: вернул ли Handler SKIP_DEFAULT или EXEC_DEFAULT


--------------------
HoMM 3 HD:
http://sites.google.com/site/heroes3hd
последняя версия - 3.61f


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
baratorch
сообщение 11 Nov 2017, 21:21
Сообщение #31

Immortal
Сообщений: 2 373
Спасибо сказали: 4534 раза




переделал свой тест

добавил в тестируемый код pushfd - popfd
и добавил еще 2 варианта


Код
pushad...  : 10172
push edi...: 9781
push eax...: 9906
old...  : 12172
new...  : 10984

Код
pushad...  : 5912
push edi...: 5506
push eax...: 5398
old...  : 7566
new...  : 6053


old - это то как реализовано перемещение регистров в стек и обратно в последнем опубликованном patcher_x86 4.2.8
через кучу, т.е. некоторые значения проходят путь: регистр -> куча -> стек -> куча -> регистр.

new - это новая реализация: регистр -> стек -> стек -> регистр

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


--------------------
HoMM 3 HD:
http://sites.google.com/site/heroes3hd
последняя версия - 3.61f


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 11 Nov 2017, 23:35 (Сообщение отредактировал Berserker - 12 Nov 2017, 00:17)
Сообщение #32

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Цитата
если да, то такое нельзя сделать.

Именно так.

адрес затёртого кода, хранимого в мосте:
[затёртая команда 1]
[затёртая команда 2]
[возврат на адрес после затёртых команд]

Цитата
В самом мосте адрес возврата у тебя не пушится.

У меня мост реализован в виде CALL. Адрес возврата автоматически попадает в стек. Его можно изменить в обработчике через Context.RetAddress := новое значение.
Цитата
Значит перенаправление на сам мост из оригинального кода идет посредством call?

Да.

Цитата
У меня же перенаправление на мост идет посредством jmp
а адрес возврата помещается в контекст внутри моста.

Да, видел.

Цитата
Второе. Я правильно понимаю что в твоем HOOKTYPE_BRIDGE мосте, если Handler возвращает EXEC_DEFAULT,
то мост игнорирует адрес возврата из контекста и прыгает обратно туда, куда должен по умолчанию?

Да, именно так. Затёртый код мог содержать команды, изменяющие ESP, я уже сталкивался с такими багами. Поэтому адрес возврата жёстко забит в MOV EAX, [адрес] при EXEC_DEFAULT.

Цитата
У меня же в мост прыгает по адресу возврата из контекста , который мы возможно изменили внутри Handler, в любом случае: вернул ли Handler SKIP_DEFAULT или EXEC_DEFAULT

Были баги, кода перезаписал места вида ADD ESP, XXX или PUSH XXX или POP XXX. У тебя такие проблемы исключены?


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
baratorch
сообщение 12 Nov 2017, 06:48
Сообщение #33

Immortal
Сообщений: 2 373
Спасибо сказали: 4534 раза




Цитата
адрес затёртого кода, хранимого в мосте:
[затёртая команда 1]
[затёртая команда 2]
[возврат на адрес после затёртых команд]

я не понимаю зачем давать пользователю LoHook'a возможность обращаться к адресу затертого кода в мосте
и зачем вызывать такое внутри Handler, ведь на момент вызова этого будет неактуальным и непредсказуемым содержимое регистров.

после return EXEC_DEFAULT в Handler
в мосте происходит следующее:
1. значения всех регистров из контекста (HookContext::eax, ...) копируются в соответствующие регистры
2. выполняется затертый код (затертая команда 1, затертая команда 2, ...)
3. прыжок на HookContext::return_address. Если внутри Handler он не изменялся, то это будет адрес после затёртых команд в исходном коде.
Что тут тебе еще может быть нужно, я не понимаю.

Цитата
Были баги, кода перезаписал места вида ADD ESP, XXX или PUSH XXX или POP XXX. У тебя такие проблемы исключены?

проблем c уcтановкой ЛоуХука на команды изменяющие esp - нет.


Цитата(baratorch)
Код
int __stdcall Handler(LoHook* h, HookContext* c)
{
какой-то код...
...
выполнить затертое
...
какой-то код...
}

Здесь главное то, что после выполнения затертого еще можно выполнить еще какой-то свой код внутри Handler.
Под затертым я имею в виду реально затертое (это может быть джамп другого хука, о котором мы не знаем),
А так-то мы всегда можем в Handler продублировать затираемый оригинальный код манипуляциями с HookContext::eax, ...


--------------------
HoMM 3 HD:
http://sites.google.com/site/heroes3hd
последняя версия - 3.61f


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
Ben
сообщение 12 Nov 2017, 10:11
Сообщение #34

Advanced Member
Сообщений: 118
Спасибо сказали: 62 раза




Berserker, вы могли бы подсказать, как использовать патчер для моддинга игры, отличной от Heroes 3, например, Heroes 2, либо для моддинга Heroes 3, но без HD мода ?
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 12 Nov 2017, 12:32
Сообщение #35

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




Бара, поделишься самой последней версией патчера, по которой тесты делал? )
И ещё маленький вопрос, у тебя компилятор может детальный map-файл сгенерировать для patcher_x86.dll?

Цитата
Berserker, вы могли бы подсказать, как использовать патчер для моддинга игры, отличной от Heroes 3, например, Heroes 2, либо для моддинга Heroes 3, но без HD мода ?

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


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
Ben
сообщение 12 Nov 2017, 13:34
Сообщение #36

Advanced Member
Сообщений: 118
Спасибо сказали: 62 раза




Цитата(Berserker @ 12 Nov 2017, 12:32) *
Вы знаете, это пришлось бы писать очень длинную инструкцию, чего сейчас делать не могу. Обычно требуется сперва навык работы в отладчике, ручной установке патчей и чуть-чуть программной, чтобы вовсю использовать такие инструменты.


Навыки работы в отладчике есть. А если не детальную инструкцию, а какие-то общие принципы/этапы ?


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 12 Nov 2017, 14:40 (Сообщение отредактировал Berserker - 12 Nov 2017, 14:33)
Сообщение #37

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




У Вас должна быть возможность подгружать свои библиотеки/плагины для изменяемой игры. Поэтому первое, что пишется — это загрузчик. Он либо внедряется в начало исполняемого кода оригинального файла, как Эра:
https://yadi.sk/i/gk4G7ak83PcxrM
(в коде инициализации библиотеки нужно выполнить затёртые команды и вернуться)

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



Вот сам загрузчик, принимающий путь к исполняемому файлу и внедряемой библиотеке через командную строку. Антивирусы на этот файл смотрят с нескрываемым диагнозом «вирус», поскольку можно запустить любой процесс, внедрив в него любую библиотеку, что чревато.
https://yadi.sk/d/zBeSI8uk3Pcy8Q

Далее Ваш плагин, используя patcher_x86 или другое средство для установки заплаток устанавливает множество перехватчиков по коду, которые будут генерировать события — вести на Ваши обработчики. Событие: «щелчок мышью», событие «оценка ИИ стоимости объекта» и т.д. Для этого предназначены прежде всего WriteHiHook (вы перехватываете начало функции, можете вызвать оригинальную, можете весь функционал заменить) и WriteLoHook (установить перехватчик в любом месте кода с возможность вызова затёртого кода перед возвратом). Примеры плагинов можете попросить у feanor, Sav, SyDr. Небольшие их модули точно используют патчер.

Вот и всё. Загрузчик — своя библиотека — установка перехватчиков — обработка событий.

Цитата
я не понимаю зачем давать пользователю LoHook'a возможность обращаться к адресу затертого кода в мосте

Редкие случаи. До перевода части кода на патчер это был функционал SPLICE. Если перехватчик установлен на первые команды функции, то можно вызывать как оригинальную функцию, так и перехваченную.
Если перехвачено место, куда идёт несколько прыжков, то адрес в одном из прыжков можно заменить на адрес выполнения затёртого кода, а в другом оставить адрес перехваченного кода. Будут две разные ветви исполнения. Я реально использовал только SPLICE-подобную механику и то, до перехода на патчер.

Тем не менее, в АПИ Эры функция возвращает указатель на выполнение затёртого кода. Как этот указатель будет использоваться — решает пользователь.

Цитата
проблем c уcтановкой ЛоуХука на команды изменяющие esp - нет.

Значит у тебя более продвинутая реализация, это хорошо.


--------------------


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post
Ben
сообщение 12 Nov 2017, 14:56
Сообщение #38

Advanced Member
Сообщений: 118
Спасибо сказали: 62 раза




Спасибо ! Очень интересно !
Go to the top of the pageAdd Nick
 
+Quote Post
Berserker
сообщение 12 Nov 2017, 15:55
Сообщение #39

Immortal
Сообщений: 1 428
Спасибо сказали: 898 раз




На здоровье! smile2.gif Успехов Вам )


--------------------
Go to the top of the pageAdd Nick
 
+Quote Post
Ben
сообщение 12 Nov 2017, 17:08
Сообщение #40

Advanced Member
Сообщений: 118
Спасибо сказали: 62 раза




Цитата(Berserker @ 12 Nov 2017, 14:40) *
Далее Ваш плагин, используя patcher_x86 или другое средство для установки заплаток устанавливает множество перехватчиков по коду, которые будут генерировать события — вести на Ваши обработчики.



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


Спасибо сказали:
Go to the top of the pageAdd Nick
 
+Quote Post

3 страниц V  < 1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 7 December 2019 - 00:48
Copyright by Алексей Крючков
Strategy Gamez by GrayMage
Programming by Degtyarev Dmitry
  Яндекс.Метрика