Current time: 29.11.2024, 09:23 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
patcher_x86.dll
» версия 2.8
Author Message
Berserker Offline
Administrators

Posts: 16657
Post: #46

EXEC_DEFAULT = 1;
NO_EXEC_DEFAULT = 0;

Проверка в коде патчера на 1 не есть хорошо. Нужно сравнивать с нулём. Так работает тип bool: 0 = ложь, остальное - истина.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
26.09.2013 18:44
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #47

Ещё не хватает возможности в параметрах записи высокоуровневого перехватчика пользовательский указатель, который будет сохранён в структуре перехватчика и по которому можно было бы определить, с какой целью ставился перехват и кто его клиент. Что=то вроде HiHool->UserData.

Не хочется также изобретать велосипед по поводу генерации журнала о вылете. Может быть оформить эту часть хд в виде плагина?


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
10.10.2013 19:43
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #48

Quote:Ужаснулся, глянув в код низкоуровневого перехватчика. Регистры не в стеке сохраняются и передаются, а в глобальной памяти. Это значит, что рекурсивный вызов перезатрёт их подчистую!

Code:
MOV [DWORD 4978BC8],EAX
   MOV [DWORD 4978BCC],ECX
   MOV [DWORD 4978BD0],EDX
   MOV [DWORD 4978BD4],EBX
   MOV [DWORD 4978BD8],ESP
   MOV [DWORD 4978BDC],EBP
   MOV [DWORD 4978BE0],ESI
   MOV [DWORD 4978BE4],EDI
   MOV EAX,74C6FC
   MOV [DWORD 4978BE8],EAX
   PUSH 4978BC8
я так понял речь о мосте LoHook хука.

во-первых, регистры сохраняются не в глобальной памяти а в памяти выделенной для конкретного объекта LoHook.
точно так же и память под мост выделена для каждого конкретного LoHook объекта и сам мост уникален для каждого экземпляра LoHook.
То есть получается что каждый мост каждого LoHook объекта работает со своей областью памяти для хранения значений регистров.

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

в-третьих, один патч (с собственным одним мостом и объектом HookContext) невозможно применить дважды ни к одному и тому же адресу ни к разным адресам. то есть рекурсивное выполнение кода моста невозможно.

На практике все прекрасно, что подтверждает правильность реализации.

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


Quote:Проверка в коде патчера на 1 не есть хорошо. Нужно сравнивать с нулём. Так работает тип bool: 0 = ложь, остальное - истина.
поправил в версии 2.1

Quote:Ещё не хватает возможности в параметрах записи высокоуровневого перехватчика пользовательский указатель, который будет сохранён в структуре перехватчика и по которому можно было бы определить, с какой целью ставился перехват и кто его клиент. Что=то вроде HiHool->UserData.
не совсем понял зачем это нужно. можно абстрактный пример?...
ни внутри хд, ни в нутри хоты, ни во взаимодействии до сих пор не понадобилось ничего подобного.


позже опубликую версию 2.1
(This post was last modified: 24.10.2013 21:33 by baratorch.)
24.10.2013 21:32
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #49

Quote:во-вторых, я не понимаю о какой рекурсии может идти речь.
Процедура Х (...)
команда 1
низкоуровневый перехватчик №1
команда 2...

Низкоуровневый перехватчик №1(...)
вызвать процедуру Х(...); рекурсия !!!
другие команды...

Многие АПИ и часть алгоритмов требует рекурсии. Нельзя, чтобы перехватчик по одному адресу сохранял контекст в одной и той же области памяти. В такой перехватчик невозможно зайти дважды, не затерев предыдущий контекст. В Эре контекст сохраняется через PUSHAD и таких проблем нет.

Quote:не совсем понял зачем это нужно. можно абстрактный пример?...
Положим, есть скриптовый язык, для примера будет ЕРМ, но только для примера. Ему предоставляется АПИ для установки перехватчика SetHook(Addr, ERM_FUNC_ID).

Реально вызывается WriteHiHook на одну общую функцию: CallErmFunc. Но так как это именно функция без привязки к данным, она не может определить, какой ERM_FUNC_ID вызывать в свою очередь ей. Для этого в ЯП используют делегаты - связку: адрес объекта + адрес метода объекта.

Иначе говоря, одна функция обслуживает десятки перехватов. Чтобы определить, кому дальше передавать управление, ей нужно проанализировать какое-то поле данных, но ничего передать не получается. А с другой стороны, всегда передаётся-таки объект Hi/LoHook. Однако он бесполезен, в нём нельзя сохранить пользовательский указатель (h->UserData = ...).


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
24.10.2013 22:38
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #50

Quote:Процедура Х (...)
команда 1
низкоуровневый перехватчик №1
команда 2...

Низкоуровневый перехватчик №1(...)
вызвать процедуру Х(...); рекурсия !!!
другие команды...

Многие АПИ и часть алгоритмов требует рекурсии. Нельзя, чтобы перехватчик по одному адресу сохранял контекст в одной и той же области памяти. В такой перехватчик невозможно зайти дважды, не затерев предыдущий контекст. В Эре контекст сохраняется через PUSHAD и таких проблем нет.
понял о какой рекурсии идет речь, но это изврат - вызывать из лоухука код, в который установлен этот лоухук.
хочу реального примера. Но посмотрю, конечно, что можно сделать.

В HiHook UserData добавлю

А так к версии 2 в патчере появились две вкусные вещи
WriteLoHookEx и WriteHexHook.


WriteLoHookEx работает так же как WriteLoHook, но позволяет полноценно работать со стеком контекста, т.е. возможно выполнение такой штуки:
Code:
int __stdcall LoHook_Func(LoHook* h, HookContext* c)
{
   ....
   c->Push(x)
   // или то же самое:
   с->esp -= 4;
   IntAt(c->esp) = x;
   ...
   return NO_EXEC_DEFAULT;
}
вот на такое эровский лоу-хук точно не способен.



а WriteHexHook устанавливает LoHook без использования высокоуровневой функции, тело хука пишется прямо в вызове WriteHexHook в машинных кодах, подобно тому как патч пишется с помощью WriteCodePatch
пример:
Code:
_PI->WriteHexHook(0x335577, NO_EXEC_DEFAULT, "FF 35 %d", &x); // push [&x]

Вот, кстати, с помощью WriteHexHook и можно самостоятельно написать свой мост к высокоуровневой функции любого содержания, в том числе и сохраняющего регистры в стеке.
(This post was last modified: 25.10.2013 08:40 by baratorch.)
25.10.2013 08:11
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #51

Quote:понял о какой рекурсии идет речь, но это изврат - вызывать из лоухука код, в который установлен этот лоухук.
   хочу реального примера. Но посмотрю, конечно, что можно сделать.
Например, FindFileInLod. А в нём if FindFileInLod(файл с альтернативным расширением или изменённым именем, то вернуть его), иначе действие по умолчанию. У меня были и другие примеры, но нужно лезть в код и искать те, где была рекурсия. При чём порой рекурсия была косвенной, когда ты вызываешь АПИ, которое дёргает ту же функцию, в которой перехват. Это нормально, ибо рекурсия не бесконечная, а ограничена условиями и проверками.

Quote:с->esp -= 4;
IntAt(c->esp) = x;

Я обычно пишу так: dec(Context.esp, 4) и pinteger(context.esp)^ := x; Вряд ли можно чем-то упростить работу с обычными адресами в памяти, но посмотрим.

Quote:В HiHook UserData добавлю
Спасибо.

Quote:Но посмотрю, конечно, что можно сделать.
PUSHAD PUSH ESP? ))


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
25.10.2013 17:42
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #52

(25.10.2013 17:42)Berserker Wrote:  
Quote: хочу реального примера.
Например, FindFileInLod. А в нём if FindFileInLod(файл с альтернативным расширением или изменённым именем, то вернуть его), иначе действие по умолчанию. У меня были и другие примеры, но нужно лезть в код и искать те, где была рекурсия. При чём порой рекурсия была косвенной, когда ты вызываешь АПИ, которое дёргает ту же функцию, в которой перехват. Это нормально, ибо рекурсия не бесконечная, а ограничена условиями и проверками.
в приведенном примере напрашивается использование хай хука на FindFileInLod. Но в любом случае я уже сделал сохранение регистров в стэке.

(25.10.2013 17:42)Berserker Wrote:  
Quote:с->esp -= 4;
IntAt(c->esp) = x;

Я обычно пишу так: dec(Context.esp, 4) и pinteger(context.esp)^ := x; Вряд ли можно чем-то упростить работу с обычными адресами в памяти, но посмотрим.
ты не понял о чем речь.
мой и твой код идентичны, дело не в простоте.
В твоем хуке по адресу (Context.esp - 4) храниться значение одного из регистров. Т.е. с каждым таким push в хуке ты будешь портить значения регистров, которые возможно соберешься использовать после такого пуша, и которые потом заPOPADишь в мосте, а за регистрами пойдут указатель на экземпляр THookHandlerArgs и адрес возврата в мост. Надеюсь, проблема понятна.

(25.10.2013 17:42)Berserker Wrote:  
Quote:Но посмотрю, конечно, что можно сделать.
PUSHAD PUSH ESP? ))
не так все просто.
В структуре HookContext патчера регистры в обратном порядке нежели в THookHandlerArgs и чтобы сохранить обратную совместимость
пушить регистры надо в обратном PUSHADу порядке.
плюс в новой версии патчера в HookContext еще и доступен для чтения/изменения регистр флагов, а он для той же обратной совместимости добавлен после поля return_address.

сама длл 2.1 и хэдер для с++ с комментариями уже готовы.
дополню твой PatchApi.pas и опубликую.
25.10.2013 20:20
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #53

Отлично.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
25.10.2013 22:04
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #54

версия 2.1

библиотека + SDK + исходники

чейнджлог:
Code:
2.1

[-] чтение/изменение esp регистра в LoHook хуке работало неверно

[+] добавлены функции
    PatcherInstance::WriteHexHook
    PatcherInstance::CreateHexHook
    
    эти функции позволяют установить самый примитивный хук
    а именно LoHook без высокоуровневой оболочки-функции.
    тело хука пишется прямо в вызове WriteHexHook или CreateHexHook
    таким же образом как пишется патч с помощью WriteCodePatch или CreateCodePatch

[+] В любом LoHook хуке теперь доступен для чтения/изменения регистр флагов процессора (расширена структура HookContext)

[+] LoHook теперь хранит экземляр HookContext в стеке, а не по фиксированному адресу, что позволяет корректно рекурсивно выполнять LoHook хук.

[+] теперь внутри функции сработавшей по LoHook хуку можно использовать операции с помещением данных в стэк контекста хука, аналогичные команде процессора PUSH.
    размер памяти, доступной для такого помещения в стэк контекста ограничен 128 байтами для хука, созданного с помощью методов PatcherInstance::WriteLoHook и PatcherInstance::CreateLoHook, и произволен для хука, установленного с помощью новых методов
    PatcherInstance::WriteLoHookEx
    PatcherInstance::CreateLoHookEx.

[+] добавлена функция:
    PatcherInstance::BlockAt
    которая запрещает данному экземпляру PatcherInstance устанавливать по заданному адресу патчи/хуки

[+] добавлены функции
    HiHook::SetUserData
    HiHook::GetUserData

[+] расширен функционал PatcherInstance::WriteDataPatch и PatcherInstance::CreateDataPatch
    - добавлен формат символ %s (string) - копирует си-строку из аргумента

Добавил SetUserData и GetUserData к HiHook, но функцию установки HiHook хука с одновременным указанием UserData писать не стал.
Ее можно быстро написать самому, используя PatcherInstance::CreateHiHook, HiHook::SetUserData и HiHook::Apply

Есть один нюанс.
В хота 1.2 и в ХД+ версий ниже 3.59 есть критический баг в использовании патчера, который прощали старые версии, но не прощает 2.1
(This post was last modified: 26.10.2013 21:51 by baratorch.)
26.10.2013 21:47
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #55

Quote:Добавил SetUserData и GetUserData к HiHook, но функцию установки HiHook хука с одновременным указанием UserData писать не стал.
   Ее можно быстро написать самому, используя PatcherInstance::CreateHiHook, HiHook::SetUserData и HiHook::Apply
Согласен. Не стал писать это же предложение.

Quote:В хота 1.2 и в ХД+ версий ниже 3.59 есть критический баг в использовании патчера, который прощали старые версии, но не прощает 2.1
Если есть двоичная несовместимость, можно было и в LoHook использовать PUSHAD (что быстрее ручного порегистрового сохранения). А с другой стороны, это нужно кучу всего обновлять. Меня просто всё время точит червь оптимизации )))

Кстати, использовал уже несколько раз исходники ХД при поиске информации. Так что открытые материалы имеют таки синергетический эффект.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
26.10.2013 22:12
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #56

версия 2.2

библиотека + SDK + исходники

чейнджлог:
Code:
2.2
[-] LoHook не сохранял регистр флагов
28.10.2013 12:46
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #57

версия 2.3

библиотека + SDK + исходники

чейнджлог:
Code:
2.3
[+] добавлены функции
    Patcher::VarInit
    Patcher::VarFind
    и тип Variable для работы с общими "переменными" для всех текущих клиентов patcher_x86.dll
[+] функция SaveDump сохраняет в файл после списка всех установленных патчей список всех "переменных" с их текущими значениями.

patcher_x86.hpp для С++ дополнен еще и методами Patcher::VarGetValue(name, default_value) и Patcher::VarValue(name), которых
нет в PatchApi.pas
но подобные методы можно написать самому.

HD версии 3.660 теперь использует патчер 2.3 и использует его общие "переменные".
Экспортируемые _HD3_.dll методы HdCommon_Get и HdCommon_Set оставлены для обратной совместимости, но теперь являются оболочками новых методов патчера.
напомню, с помощью [SHIFT]+[CTRL]+[ALT]+[DEL] в ХД вызывается краш c генерацией логов,
и в сгенерированном patcher_x86 dump.txt можно посмотреть все общие "переменные" и их значения
Теперь чтобы использовать "переменные" ХД, не нужно грузить _HD3_.dll и импортировать ее функции.

еще один шаг для взаимодеийствия и дружбы модов.
(This post was last modified: 03.12.2013 16:40 by baratorch.)
03.12.2013 16:39
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #58

Аналог общей библиотеки-реестра выходит (хранение ключей-значений с интерфейсом доступа к ним).


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
03.12.2013 19:21
Find all posts by this user Quote this message in a reply
Arseniy Offline

Posts: 123
Post: #59

У меня, может, немного нубский вопрос, но я пока не понял, как выглядит система с патчером в действии.
Вот если я хочу использовать вместе свой мод, который будет прописывать какие-то значения в игре с помощью патчера, и HD Mod.
Как, что и к чему нужно подключать?
И второй вопрос про jump хуки в код. Если я правильно понимаю, то функции патчера просто позволяют извлечь текущий контекст в ассеблеровском виде, то есть нужно доподлинно знать, что именно сейчас лежит в регистрах и за что отвечает?


- Как я сегодня балагурю?
- Вы прекрасны, сир! (с)
31.03.2014 12:28
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16657
Post: #60

Погляди что-ли плагины Феанора с исходным кодом в качестве примеров.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
31.03.2014 21:39
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2024 MyBB Group