Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

DF2 :: ФОРУМЫ _ HD-мод _ patсher_x86

Автор: baratorch 21 Oct 2016, 13:41

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


С хд и хотой поставляется уже патчер версии 4.2.2
в нем теперь нет понятия неотменяемого патча.
появились методы WriteAsmPatch и WriteAsmHook, которые позволяют писать конструкции типа:

Код
_PI->WriteAsmHook(0x4F8662,
    "push 1",
    "call %d", Sleep,
    "_ExecDefault",
    0);


Код
            _PI->WriteAsmPatch(0x59D715,
                "MOVZX ESI,BYTE PTR DS:[EAX + EBX - 0x159]",
                "MOV EAX, DWORD PTR DS:[EBX + 0x60]",
                "TEST EAX,EAX",
                "JNZ SHORT 0x59D72A",
                "CMP DWORD PTR DS:[EBX + 0x74], 1",
                "JE SHORT 0x59D735",
                "CMP EAX, 1",
                "JNZ SHORT 0x59D7A9",
                "CMP DWORD PTR DS:[EBX + 0x74], 2",
                "JNZ SHORT 0x59D7A9",
                "PUSH DWORD PTR DS:[EBX + 0x6C]",
                "PUSH DWORD PTR DS:[EBX + 0x68]",
                "MOV ECX, DWORD PTR DS:[EBX + 0x64]",
                "PUSH ESI",
                "CALL 0x4E54B0",
                "MOV ECX, DWORD PTR DS:[EBX + 0x64]",
                "MOVSX ECX, WORD PTR DS:[ECX + 0x18]",
                "CMP EAX, ECX",
                "JG SHORT 0x59D762",
                "MOV EDX, DWORD PTR DS:[EDI + 0x8]",
                "MOVZX EAX, BYTE PTR DS:[EDX + EBX - 0x159]",
                0);


Так же в новом патчере практически устранена разница между Code и Data патчами. Т.е. Code патч всегда пишет код именно так как мы задумали, без неочевидных конвертаций относительных адресов.
И еще ряд мелких правок и багфиксов.

***

Кому-нибудь это вообще интересно?
Расписывать ли мне здесь общую документацию, изменения и документацию к новому функционалу?
Кто-нибудь, кроме меня, Сава и феанора еще пользуется патчером? feanor, тебе это интересно?
Просто у меня весьма ограничено свободное время и совершенно не хочется его тратить впустую.

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

Автор: Etoprostoya 21 Oct 2016, 14:10

А patcher_x64 сложно будет сделать?

Автор: igrik 21 Oct 2016, 14:18

Я пользуюсь патчером. И да - мне это интересно.
Но пользуюсь я им не настолько глубоко, чтобы делать что-то грандиозное.

Автор: baratorch 21 Oct 2016, 16:43

Цитата(Etoprostoya @ 21 Oct 2016, 16:10) *
А patcher_x64 сложно будет сделать?

У меня лично в нем нет потребности и я не знаю особенностей x64
И если учесть что надо будет писать другие

то да, для меня сделать сложно. Но вообще - реально.

Основные проблемы, короче, - это дизассемблер длин и ассемблер, остальное - уже решаемо мной.
Причем дизассемблер длин нужен компактный и быстрый, писанный на асм/си/си++.
А ассемблер тоже нужен с минимальнейшим функционалом, лишь бы все инструкции понимал. + должен быть написан на си/си++. Я когда искал подходящего кандидата для x86 натыкался либо на каких-то громоздких суперфункциональных чудовищ либо на ущербов, которые даже не все 86ые инструкции переваривали. Ассемблер из OllyDbg - идеален для наших задач, но я нашел его не сразу. Насколько мне известно подобного для х64 - нет (в смысле - открытых исходников).

В принципе можно обойтись и без ассемблера, как без него обходился патчер x86 до версии 4.0. Он нужен только чтобы полностью повторить имеющийся сейчас функционал.

Автор: XEPOMAHT 21 Oct 2016, 16:44

Теоретически не представляю как пользоваться patсher_x86, да хотя бы как просто подключить его к третьим Героям без HD-мода или ХотА. Да и когда отсутствует разобранный диассамблированный код третьих Героев, не знаю, что смогу наменять в Героях, скорее добавлю какие-нибудь баги и вылеты. И на каком языке что-то писать под patсher_x86 (ERM-костылями неудобно, а Си-крест-крест - это слишком высокоуровнево для низкоуровневых представителей человечества) Поэтому для моддинга ERA/MOP only, patсher_x86 is not. И документация к patсher_x86 вряд ли поможет зелёным новичкам типа меня - это уже бесполезно в силу древности игры и минимальному интересу к моддингу у игроков в Героев в целом (может быть patсher_x86 может поднять интерес к моддингу Героев, но вероятность этого крайне низка - эта вещь сделана для программистов/хакеров, а не для обычных моддеров, лично для меня patсher_x86 не представляет интереса, когда есть более понятные и доступные для использования в третьих Героях платформы ERM/WERD), тем более нужно им понадобиться очень подробная документация с примерами "patсher_x86 для чайников" - может ли такую написать профессиональный программист (по себе могу сказать, что у меня ушло много месяцев на расжёвывания документации по ERM, вряд ли получится разобраться в документации patсher_x86, если она всё-таки будет написана)?

Автор: baratorch 21 Oct 2016, 16:55

XEPOMAHT, да, pather_x86 - это инструмент именно для программиста, причем такого, кто готов реверсить код, работая с отладчиками и дизассемблерами.
просто патчер облегчает (ускоряет!) работу, по реверсингу в том числе.
Мне и интересно сколько здесь таких.

Автор: t800 21 Oct 2016, 17:39

Цитата(baratorch @ 21 Oct 2016, 19:55) *
XEPOMAHT, да, pather_x86 - это инструмент именно для программиста, причем такого, кто готов реверсить код, работая с отладчиками и дизассемблерами.
просто патчер облегчает (ускоряет!) работу, по реверсингу в том числе.
Мне и интересно сколько здесь таких.


Здравствуйте! А каким образом Ваш патчер ускоряет работу по ререрсингу? Просто летом в свою IDA поставил плагин от James Koppel https://www.hex-rays.com/contests/2011/index.shtml им можно прямо в дебагере патчить и сразу смотреть что получилось.

ЗЫ Если еще если вы дадите инструкцию с каким-нибудь примерам как ползоваться и что можно интересного сделать Вашим патчером, то если хотете я мог бы мог сделать видеоурок про Ваш парчер. Вот.

Автор: Etoprostoya 21 Oct 2016, 17:42

В составе Object File Converter есть дизассемблер с открытым исходным кодом http://www.agner.org/optimize/#objconv Я с ним детально не разбирался, но там очень широкий (если не полный, вплоть до всяких FMA, AVX, AVX512) диапазон распознаваемых и дизассемблируемых команд.
Вот сейчас взглянул на фрагмент кода (opcodes.cpp):


Ну и вообще, у Агнера Фога много хороших книжек на тему оптимизации ассемблерной, сишной, вместе с примерами и библиотеками.

Автор: feanor 21 Oct 2016, 17:52

Цитата
feanor, тебе это интересно?

В принципе, интересно, но если инклуд будет комментирован на уровне прошлых версий - можно и обойтись, если не до того.

Автор: baratorch 22 Oct 2016, 00:53

Положил на дропбокс патчер 4.2.3 (отличается от 4.2.2 меньшим размером) и обновленный хэдер для Си++:
https://dl.dropboxusercontent.com/u/56675299/patcher_x86%204.2.zip

Итак, изменения версии 4.2 относительно 2.8:

[!] Переработана структура хранения примененных патчей.
Теперь патчи группируются не по адресу установки, как было, а по динамическим диапазонам (отрезкам): начальный адрес - конечный адрес.
В одном таком динамическом отрезке хранятся все пересекающиеся патчи.
Если применяется один патч поверх другого со смещением или отличающийся по размеру - то этот патч помещается в тот же отрезок, при этом отрезок расширяется (меняются его начальный адрес и конечный адрес)
Пока (в версии 4.2), отрезки при применении патчей - создаются, расширяются. Но не уменьшаются и не удаляются при отмене.
Т.е. возможна ситуация когда в одной стопке хранятся не пересекающиеся патчи (когда патч пересекающий их обоих отменен).

В связи с этим теперь:
- можно отменить любой патч, в том числе и перекрытый другим со смещением. FIXED патчей теперь нет.
- методы, GetLastPatchAt GetFirstPatchAt, все зависимые (UndoAllAt и пр.) теперь ищут патч не по адресу установки, а по попаданию в существующий диапазон (в patcher_x86.cpp хэдере используется термин "в окрестности адреса address" вместо "по адресу address").
(методы BlockAt и BlockAllExcept по прежнему оперируют адресами установки)
- изменились форматы дампа и лога патчера.

дамп:

Код
[ ][ ][ ] 3: (00401510 05 HiHook 0000001843 - HD.HotA), (00401510 05 HiHook 0000001845 - HD.HotA), (00401510 05 HiHook 0000002968 - HD.Af)
[ ][s][t] 2: (00424389 04 Patch  0000003595 - HotA), (00424389 06 LoHook 0000003596 - HotA)
[ ][s][t] 2: (0042440B 03 Patch  0000003597 - HotA), (0042440B 05 LoHook 0000003598 - HotA)
[a][s][t] 2: (005A8048 05 HiHook 0000002731 - HD.HotA), (005A8014 64 Patch  0000005395 - HotA)
[a][s][ ] 2: (005F946E 03 Patch  0000001782 - HD.HotA), (005F9470 01 Patch  0000003184 - HD.True32)

[a] значит в стопке есть патчи не совпадающие по адресам установки
[s] значит в стопке есть патчи не совпадающие по размеру
[t] - по типу
число после типа патча - это общая глобальная очередность применения.

в логе ворнинги теперь выглядят так:

Код
WARNING! [a][s][t]: Applying LoHook (00432E91 10 - HotA) over already applied Patch  (00432E97 04 - HotA).




[!] теперь для установки EXTENDED_(и SAFE_) CDECL_ HiHook-хуков можно использовать и __stdcall функции (возможность использовать __cdecl функции сохранена)
- это было продекларировано для более ранних версий патчера, но с какой-то версии сломалось и не работало.
Таким образом для EXTENDED_ хука хук-функция имеет единый вид: ? __stdcall new_func(HiHook* hook, ?)

[-] исправлен баг с применеием-отменой-применением хуков поверх длинных патчей (размером больше 5, на практике это серии NOP'ов)

[!] изменена часть мостов хай-хуков, позволяющая устанавливать хуки на рекурсивно выполняющиеся функции. Теперь для не рекурсивных вызовов выполняется один (максимально быстрый и безопасный) код, а для рекурсивных - другой. Поскольку не рекурсивных функций обычно 99+% , такой подход очень сильно повлиял на быстродействие и стабильность.

[ ] теперь патчер жрет на ~ 1.2 - 1.5 мегабайта оперативы меньше (в сравнение с версиями 2.7, 2.8, ...).

[ ] практически устранена разница между CODE_ и DATA_ патчами. Т.е. Code патч всегда пишет код именно так как мы задумали, без неочевидных конвертаций относительных адресов. Таким образом вызовы PatcherInstance::Write(a, d, CODE_) и PatcherInstance::Write(a, d, DATA_) теперь идентичны.

[+] добавлены новые методы PatcherInstance: WriteAsmPatch и WriteAsmHook (а так же CreateAsmPatch и CreateAsmHook):


***

в хэдере в методе
virtual LoHook* __stdcall WriteLoHook(_ptr_ address, _LoHookFunc_ func) = 0;
изменен тип func с void* на _LoHookFunc_, чтобы
в MS VC++ компиляторах (в VC++ 2010 и новее) методу можно было скармливать лямбды:

Код
        _PI->WriteLoHook(0xAABBCC, [](LoHook* h, HookContext* c) -> int
        {
            o_MsgBox("Hello from lambda LoHook!");
            return EXEC_DEFAULT;
        });


так же для MS VC++ 2010 и новее
я сделал такой макрос (через лямбду опять же):

чтобы можно было ставить "быстрые инлайн" хайхуки:

Код
                Create_HiHook(0xAABBCC, SPLICE_, EXTENDED_,
                    int, __thiscall, FuncName, (int in, int in2),
                    {
                        //...
                        return DefaultFunc(in, in2);
                    }
                )->ApplyInsert(0);


правда пользоваться ими для написания больших хуков неудобно, потому что IntelliSence не работает как надо внутри.


***

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

Автор: feanor 22 Oct 2016, 03:15

Лямбды, ня!

Автор: baratorch 25 Oct 2016, 08:05

Цитата(t800 @ 21 Oct 2016, 19:39) *
Здравствуйте! А каким образом Ваш патчер ускоряет работу по ререрсингу?

Несколько примеров из личного опыта:

1. Дано:
В ИДА мы нашли конструктор интересующего нас объекта, в конструкторе нашли виртуальную таблицу, отреверсили определенную функцию F (т.е. +- поняли что она делает) в этой виртуальной таблице.
Найти: откуда в программе эта функция F вообще вызывается?
Решение: ставим с помощью патчера SPLICE_ EXTENDED_ хук на эту функцию F
Внутри хука делаем запись в лог (например в ХД я использую вывод в консоль) результат hook->GetReturnAddress()
так же при этом мы можем в лог писать значения входных аргументов и результат выполнения функции F, например.
Запускаем программу (Героев), совершаем действия, смотрим лог.



2. Нам нужно в отладчике (OllyDbg) поставить брэйкпоинт на чтение или изменение определенного поля определенной структуры в определенный момент (т.е. после выполнения определенных действий).
Решение: ставим хук на нужное место в коде (это место, понятно, должно быть отреверсено), делаем вывод адреса нтересующего нас поля (обычно адрес - динамический), нужной структуры, например с помощью MessageBox
- что одновременно "ставит на паузу" выполнение программы (Героев), позволяя нам поставить бряк в отладчике на нужный адрес. Постановка на паузу особенно актуальна, если интересующее нас поле ДО интересующего нас момента может меняться в программе хренову тучу раз.
Нажимаем ОК в мессадж-боксе - смотрим где сработал бряк.

3. Установка элементарной точки трассировки:

Этого можно было бы добиться установкой бряка в отладчике. Но бряк останавливает выполнение программы, и в случае когда код выполняется много раз в короткий промежуток времени, такой метод (установка ьряка) совсем не юзабелен.

Думаю, те, кто занимается реверсингом эти методы (о)ценят. Хотя возможно я не все знаю о возможностях Olly и IDA и их инструментами можно достичь того же. Если так, то просветите меня, пожауйста.


Цитата
Просто летом в свою IDA поставил плагин от James Koppel https://www.hex-rays.com/contests/2011/index.shtml им можно прямо в дебагере патчить и сразу смотреть что получилось.
я плагин не смотрел, но позволяет ли он менять оригинальный код на новый большей длины? позволяет ли писать новый код не на асме а на с++, скажем?
Если нет, то этот плагин совсем несравним с патчером.

UPD.
сейчас в сети нашел как поставить брейкпоинт на чтение/зменение памяти программно из нашего кода
- в сочетании с Примером 2 вообще удобнота будет.

Автор: igrik 25 Oct 2016, 17:55

А в чем принципиальная разница Hi и Lo хуков?
И еще вопрос: можно ли как-то вывести диалог, с выбором одного из 7-ми элементов. Элементы - изображения ресурсов (дерево и т.д.). (Хотя думаю вопрос не совсем в теме)

Автор: t800 25 Oct 2016, 21:43

Цитата(baratorch @ 25 Oct 2016, 11:05) *
Цитата
Просто летом в свою IDA поставил плагин от James Koppel https://www.hex-rays.com/contests/2011/index.shtml им можно прямо в дебагере патчить и сразу смотреть что получилось.
я плагин не смотрел, но позволяет ли он менять оригинальный код на новый большей длины? позволяет ли писать новый код не на асме а на с++, скажем?


Нет не позволяет, только каманды asm можно писать


Цитата(baratorch @ 25 Oct 2016, 11:05) *
Цитата(t800 @ 21 Oct 2016, 19:39) *
Здравствуйте! А каким образом Ваш патчер ускоряет работу по ререрсингу?

Несколько примеров из личного опыта:

1. Дано:
В ИДА мы нашли конструктор интересующего нас объекта, в конструкторе нашли виртуальную таблицу, отреверсили определенную функцию F (т.е. +- поняли что она делает) в этой виртуальной таблице.
Найти: откуда в программе эта функция F вообще вызывается?
Решение: ставим с помощью патчера SPLICE_ EXTENDED_ хук на эту функцию F
Внутри хука делаем запись в лог (например в ХД я использую вывод в консоль) результат hook->GetReturnAddress()
так же при этом мы можем в лог писать значения входных аргументов и результат выполнения функции F, например.
Запускаем программу (Героев), совершаем действия, смотрим лог.


Может я что-то не понял, а разве по Блок Схеме в IDA нельзя просто по стрелочке глянуть откуда функция F вызывается?

Автор: tolich 25 Oct 2016, 23:39

Цитата(t800 @ 25 Oct 2016, 21:43) *
Может я что-то не понял, а разве по Блок Схеме в IDA нельзя просто по стрелочке глянуть откуда функция F вызывается?
Только статические вызовы функций. Динамические вызовы, т.е., через указатель на функцию и вызовы виртуальных функций в статике в принципе не отследить.

Автор: baratorch 26 Oct 2016, 08:57

Цитата
А в чем принципиальная разница Hi и Lo хуков?

HiHook - это "высокоуровневый" хук. Он может ставиться только на функцию.
SPLICE_ - на саму функцию.
CALL_ - на ее конкретный явный вызов (call 0xAABBCC или call dword ptr [0xAABBCC])
FUNCPTR_ - на указатель, т.е. например на позицию в виртуальной таблице или таблице импорта, или на колбэк, передаваемый аргуменом в другую функцию).

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

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

LoHook - это, соответственно, "низкоуровневый" хук. Его мы можем поставить вообще на любое место в коде. При этом мы получаем возможность работать с регистрами процессора как с переменными, используя их в нашем (допустим С++) коде и можем менять адрес возврата.
LoHook - гораздо более мощный и универсальный инструмент, в сравнение с HiHook'ом. Им можно решать любые задачи (даже те что решают SPLICE_ и CALL_ хайхуки).

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


Цитата
И еще вопрос: можно ли как-то вывести диалог, с выбором одного из 7-ми элементов. Элементы - изображения ресурсов (дерево и т.д.). (Хотя думаю вопрос не совсем в теме)

можно, конечно. Может быть найду время и выложу UI SDK для героев с примерами.

Автор: igrik 26 Oct 2016, 10:24

Цитата(baratorch @ 26 Oct 2016, 08:57) *
Цитата(igrik)
И еще вопрос: можно ли как-то вывести диалог, с выбором одного из 7-ми элементов. Элементы - изображения ресурсов (дерево и т.д.). (Хотя думаю вопрос не совсем в теме)

Можно, конечно. Может быть найду время и выложу UI SDK для героев с примерами.

Это было бы идеально.

Автор: AlexSpl 17 Sep 2017, 20:25

Цитата
Патчер - это инструмент для модификации любого исполняемого кода (не только героев).

Кто-нибудь может привести пример, как использовать патчер для моддинга других игр (например, Героев 2)?

Автор: baratorch 17 Sep 2017, 22:09

Цитата(AlexSpl @ 17 Sep 2017, 22:25) *
Цитата
Патчер - это инструмент для модификации любого исполняемого кода (не только героев).

Кто-нибудь может привести пример, как использовать патчер для моддинга других игр (например, Героев 2)?

Сейчас я в отпуске. Вернусь, покажу пример модинга героев 2. Я же начал делать ХД мод для двойки, но запнулся о локализацию, просто обломало ее делать. И работа дальше не пошла, хотя двойка (экзешник с сигнатурами) - благодатнейшая платформа для модинга.

Автор: AlexSpl 17 Sep 2017, 22:28

Было бы очень здорово! Патчить вручную не самое приятное занятие, а возможности патчера я уже успел оценить smile.gif

Автор: Berserker 08 Nov 2017, 16:38

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

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

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

Автор: baratorch 09 Nov 2017, 22:23

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


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

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


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

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

Здесь последний патчер версии 4.2.8, хэдер для C++ версии 4.2 и pas-файл версии 2.1:
http://heroes3towns.com/HD/Patcher_x86_SDK.zip

Автор: Berserker 10 Nov 2017, 23:33

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

Самый простой переходник:

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

skip_default:
popad
ret


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

Автор: baratorch 11 Nov 2017, 16:13

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




http://heroes3towns.com/HD/test.exe

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

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

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

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

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


***

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

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

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

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

Автор: Berserker 11 Nov 2017, 16:18

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

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

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

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

Автор: baratorch 11 Nov 2017, 16:49

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

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

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

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

Автор: Berserker 11 Nov 2017, 18:08

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

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

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

Автор: Berserker 11 Nov 2017, 18:57

Пока что вылеты. Я так понимаю, как 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

Автор: Berserker 11 Nov 2017, 19:19

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

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

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

Автор: baratorch 11 Nov 2017, 21:01

Цитата(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

Автор: baratorch 11 Nov 2017, 21:21

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

добавил в тестируемый код 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 итераций
уж в рамках героев разницей точно можно пренебречь.

Автор: Berserker 11 Nov 2017, 23:35

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

Именно так.

адрес затёртого кода, хранимого в мосте:
[затёртая команда 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. У тебя такие проблемы исключены?

Автор: baratorch 12 Nov 2017, 06:48

Цитата
адрес затёртого кода, хранимого в мосте:
[затёртая команда 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, ...

Автор: Ben 12 Nov 2017, 10:11

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

Автор: Berserker 12 Nov 2017, 12:32

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

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

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

Автор: Ben 12 Nov 2017, 13:34

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


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

Автор: Berserker 12 Nov 2017, 14:40

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

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



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

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

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

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

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

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

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

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

Автор: Ben 12 Nov 2017, 14:56

Спасибо ! Очень интересно !

Автор: Berserker 12 Nov 2017, 15:55

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

Автор: Ben 12 Nov 2017, 17:08

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



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

Автор: Ben 13 Nov 2017, 10:22

Цитата(Berserker @ 12 Nov 2017, 14:40) *
Вот и всё. Загрузчик — своя библиотека — установка перехватчиков — обработка событий.


Ну в общем, понятен принцип. Сами плагины, видимо, могут загружаться либо загрузчиком же, либо библиотекой-патчером, на усмотрение разработчика.

Автор: feanor 13 Nov 2017, 14:08

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

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

Автор: Berserker 13 Nov 2017, 16:08

Ben, если речь идёт о системе плагинов, то используйте AngelRun (или любой другой загрузчик dll в чужой процесс), а в самой dll выполните FindFirstFile/FindNextFile/FindClose в определённой папке, загружая все файлы с нужным расширением через LoadLibrary.

Автор: baratorch 14 Nov 2017, 11:23

Здесь последний патчер версии 4.2.9.1, хэдер для C++ версии 4.2 и pas-файл версии 2.1:
http://heroes3towns.com/HD/Patcher_x86_SDK.zip

Автор: Berserker 16 Nov 2017, 22:46

Бара, есть возможность скомпилировать ту же DLL с настройкой генерации detailed *.map-файла в linker?
Open the project's Property Pages dialog box. For details, see Setting Visual C++ Project Properties.
Click the Linker folder.
Click the Debug property page.
Modify the Generate Map File property.

P.S. https://yadi.sk/i/CY2S8Ku63PpTzc
Если я верно понимаю, то LoHook не подходит для многопоточных приложений — гонка данных на запись одного и того же значения в оперативной памяти по абсолютному адресу. Такие баги сложно отловить.

P.S.S. В связи с этим у меня вопрос, являются ли потокобезопасными HiHook-перехватчики? У меня модуль виртуальной файловой системы полностью работает на них. Файловые функции с разных потоков дёргаются. Единственное, что спасает — всё защищено критическими секциями.

Автор: Ben 18 Nov 2017, 18:42

Цитата(Berserker @ 16 Nov 2017, 22:46) *
Бара, есть возможность скомпилировать ту же DLL с настройкой генерации detailed *.map-файла в linker?
Open the project's Property Pages dialog box. For details, see Setting Visual C++ Project Properties.
Click the Linker folder.
Click the Debug property page.
Modify the Generate Map File property.


Map файл для версии 2.8:
https://yadi.sk/i/J-ZvmeWu3Pp79m

Автор: Berserker 19 Nov 2017, 13:51

В дополнение к предыдущему посту. Бара, ты используешь VirtualProtect для того, чтобы дать странице памяти права READ_WRITE_EXECUTE, но не возвращаешь оригинальные права обратно после применения патча. А это значит, что любая прямая запись позже в ту же страницу будет успешной, а не приводить к Access Violation. Может быть стоит возвращать странице оригинальные права после внесения правок?

Код
{!} Assert(Utils.IsValidBuf(Dst, Count));
  {!} Assert((Src <> nil) or (Count = 0));
  result := Count = 0;

  if not result then begin
    result := Windows.VirtualProtect(Dst, Count, Windows.PAGE_EXECUTE_READWRITE, @OldPageProtect);
    
    if result then begin
      Utils.CopyMem(Count, Src, Dst);
      result := Windows.VirtualProtect(Dst, Count, OldPageProtect, @OldPageProtect);
    end; // .if
  end; // .if

Автор: baratorch 19 Nov 2017, 21:25

Berserker, в патчере целиком и полностью забито на многопоточность.
Точнее в патчере:
1. нельзя создавать/ставить/отменять патчи/хуки в несколько потоков.
2. нельзя выполнять код с LoHook и HiHook (кроме DIRECT_) хуками в несколько потоков.
можно в несколько потоков выполнять Asm и DIRECT_ HiHook хуки.
3. нельзя пользоваться методами VarInit и VarFind в несколько потоков.

Цитата
В дополнение к предыдущему посту. Бара, ты используешь VirtualProtect для того, чтобы дать странице памяти права READ_WRITE_EXECUTE, но не возвращаешь оригинальные права обратно после применения патча.

Вообще-то обратно возвращаю.

Автор: Berserker 19 Nov 2017, 22:26

Понял, спасибо за разъяснения. Думаю, стоит это указать в первом посте или документации, что при необходимости поддержки многопоточности нужно использовать Asm и DIRECT_ HiHook-хуки.

Цитата
Вообще-то обратно возвращаю.

Отлично, значит переведя свои WriteCodeAt на Write я получу свои патчи в журналах патчера, не потеряв функциональности хуков Эры. С SetUnhandledExceptionFilter уже разобрался (теперь работает и твой, и мой обработчик). Скорее всего, бинарные патчи тоже пропущу через патчер.

А как насчёт map-файла? Можешь скомпилировать библиотеку с генерацией оного?

Автор: baratorch 20 Nov 2017, 03:12

Цитата
А как насчёт map-файла? Можешь скомпилировать библиотеку с генерацией оного?

map сделаю к следующей версии патчера, которая выйдет на днях.

Автор: Berserker 20 Nov 2017, 13:10

Если что, как работает DIRECT_ не ясно из доков:
DIRECT_ - применение в паскале/делфи не предполагается, в hpp тоже не нашёл )

Автор: baratorch 20 Nov 2017, 15:09

В DIRECT_ HiHook наша замещающая функция должна 100% соответствовать соглашению о вызовах замещаемой.

т.е. если мы ставим хук на __thiscall функцию, то наша должна быть тоже __thiscall, а точнее принимать первый аргумент в ecx, остальные в стеке.
если мы ставим хук на __fastcall, то наша должна принимать аргументы в ecx, edx и стеке.
если на __cdecl, то наша функция должна возвращать управление по retn, а не по retn (4 * колво аргументов в стеке) как это делают __stdcall, __fastcall, __thiscall

В VC++ нет проблем с объявлением __stdcall, __cdecl, __fastcall функций
__thiscall объявить нельзя, но вместо нее можно использовать __fastcall (a1, no_used, a2, ...)

Не знаю как с этим обстоят дела в Делфи/Паскале. С __stdcall проблем не должно быть, __cdecl вроде тоже поддерживается, а вот насчет __fastcall и __thiscall я не уверен.

DIRECT_ HiHook не передает указатель на хук в замещающую функцию и не создает никаких мостов, он передает управление сразу прямо на нашу замещающую функцию.

Автор: baratorch 22 Nov 2017, 16:07

Патчер версии 4.3 + map-файл: http://h3hota.com/HD/Patcher_x86_SDK.zip

Автор: Berserker 24 Nov 2017, 23:36

Бара, зацени: http://rgho.st/7pBPttP9k

Код
instances(44): 'D:\Heroes 3\era.dll', 'MonDescription', 'HD.Plugin.QuicksandMines', 'D:\Heroes 3\Mods\WoG\EraPlugins\erm_hooker.era', 'WoG Patcherizer', 'WoG', 'remove exe protection.bin', 'New_NPC_Dlg', 'adventure menu button.bin', 'always summon ship.bin', 'disable dracolich block.bin', 'dismiss last stack.bin', 'display primary skills over 99.bin', 'dl buttons fix.bin', 'hero screen button.bin', 'inferno gates teleports to any town.bin', 'magic button fix.bin', 'no gifts from allies.bin', 'no load game confirmation.bin', 'no real time trigger.bin', 'no retreat request.bin', 'no secondary skills limit.bin', 'phoenix buttons.bin', 'skin.bin', 'transfer last stack.bin', 'spellbook.bin', 'acredit.bin', 'ai sod radius.bin', 'enable next hero button.bin', 'enable town info.bin', 'fix erm ca b2 command.bin', 'fix erm check syntax.bin', 'fix erm ss a command.bin', 'fix erm tr r roads.bin', 'fix towers damage.bin', 'mp3 44khz patch.bin', 'no erm he f redraw.bin', 'no erm ow r redraw.bin', 'no erm scripts turning off.bin', 'no memory and hdd checks.bin', 'no multiplayer notes.bin', 'remove black screens.bin', 'skeleton transformer fix.bin', 'zvslib.bin',

  places count: 1433

  patches count: 1460


Все патчи создаются через патчер. Бинарные патчи применяются с созданием уникального экземпляра патчера для каждого файла. По F11 или вылету в папку Debug\Era попадает и список патчей.

Автор: hippocamus 25 Nov 2017, 00:08

Не вполне понимаю, что это значит, но ты, Берс, видимо смог победить некую недружелюбную систему. Заставил HD кушать bin-файлы? Она раньше это делала, а потом перестала, да.
В общем, поздравляю!

Автор: Berserker 25 Nov 2017, 03:13

Зачем же, если Эра их и так кушает? )) Скорее теперь Эра использует patcher в 95% случаев, причём с хорошей детализацией.
А поддержку bin-файлов, думаю, Бара выпилил сознательно. Это живой чит для игры, для которой он разрабатывает мультиплеерные средства и античит.

Автор: igrik 26 Sep 2018, 09:13

baratorch, а как вообще отменять патчи/хуки, созданные другой dll по определенному адресу? Например:
Мне необходимо отменить LoHook по адресу 0x5F4C99, созданный в Some.dll (которая загружена ранее, чем моя и у которой я знаю параметр "CreateInstance"), и установить по этому адресу свой патч в My.dll:

Код
_P = GetPatcher();
_MY = _P->CreateInstance("my");
_SOME = _P->GetInstance("some");

if (_SOME) {
_SOME->GetLastPatchAt(0x5F4C99)->Destroy();
}
// и применяю свой патч
_MY->WriteDword(0x5F4C99 +3, (_dword_)&myArray +4);

Форум Invision Power Board (http://nulled.cc)
© Invision Power Services (http://nulled.cc)