Skip to content

Instantly share code, notes, and snippets.

@Ginden
Created October 24, 2017 22:59
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ginden/57029632c2920a012990315dbbe579ed to your computer and use it in GitHub Desktop.
Save Ginden/57029632c2920a012990315dbbe579ed to your computer and use it in GitHub Desktop.
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// библиоотека patcher_x86.dll
// распространяется свободно(бесплатно)
// авторское право: Баринов Александр (baratorch), e-mail: baratorch@yandex.ru
// форма реализации низкоуровневых хуков (LoHook) отчасти позаимствована у Berserker (из ERA)
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// версия 4.2
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ОПИСАНИЕ.
//
// ! библиотека предоставляет:
// - удобные унифицированные централизованные
// инструменты для установки патчей и хуков
// в код целевой программы.
// - дополнительные инструменты: дизассемблер длин опкодов и функцию
// копирующую код с корректным переносом опкодов jmp и call c
// относительной адресацией
// ! библиотека позволяет
// - устанавливать как простые так и сложные патчи.
// - устанавливать высокоуровневые хуки, замещая оригинальные функции в
// в целевом коде на свои, не заботясь о регистрах процессора,
// стэке, и возврате в оригинальный код.
// - устанавливать высокоуровневые хуки один на другой
// не исключая а дополняя при этом функциональность хуков
// установленных раньше последнего
// - устанавливать низкоуровневые хуки с высокоуровневым доступом к
// регистрам процессора, стэку, затертому коду и адресу возврата в код
// - отменять любой патч и хук, установленный с помощью этой библиотеки.
// - узнать задействован ли определенный мод, использующий библиотеку
// - узнать какой мод (использующий библиотеку) установил определенный патч/хук
// - получить полный доступ ко всем патчам/хукам, установленным из других модов
// с помощью этой библиотеки
// - легко и быстро обнаружить конфликтующие патчи из разных модов
// (использующих эту библиотеку) 1) отмечаяв логе такие конфликты как:
// - устанавливаются патчи/хуки разного размера на один адрес
// - устанавливаются патчи/хуки перекрывающие один другого со смещением
// - устанавливаются патчи поверх хуков и наоборот
// а так же 2) давая возможность посмотреть дамп (общий листинг) всех патчей
// и хуков установленных с помощью этой библиотеки в конкретный момент времени.
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ЛОГИРОВАНИЕ.
//
// по умолчанию в patcher_x86.dll логирование отключено, чтобы включить его,
// необходимо в той же папке создать файл patcher_x86.ini c единственной
// записью: Logging = 1 (Logging = 0 - отключает логирование снова)
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ПРАВИЛА ИСПОЛЬЗОВАНИЯ.
//
// 1) каждый мод должен 1 раз вызвать функцию GetPatcher(), сохранив результат
// например: Patcher* _P = GetPatcher();
// 2) затем с помощью метода Pather::CreateInstance нужно создать
// экземпляр PatсherInstance со своим уникальным именем
// например: PatсherInstance* _PI = _P->CreateInstance("MyMod");
// 3) затем использовать методы классов Patсher и PatсherInstance
// непосредственно для работы с патчами и хуками
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#define _byte_ unsigned __int8
#define _word_ unsigned __int16
#define _dword_ unsigned __int32
//макросы CALL_? позволяют вызывать произвольную функцию по определенному адресу
//используются в том числе для вызова функций
//полученных с помощью HiHook::GetDefaultFunc и HiHook::GetOriginalFunc
#define CALL_0(return_type, call_type, address) \
((return_type (call_type *)(void))address)()
#define CALL_1(return_type, call_type, address, a1) \
((return_type (call_type *)(_dword_))(address))((_dword_)(a1))
#define CALL_2(return_type, call_type, address, a1, a2) \
((return_type (call_type *)(_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2))
#define CALL_3(return_type, call_type, address, a1, a2, a3) \
((return_type (call_type *)(_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3))
#define CALL_4(return_type, call_type, address, a1, a2, a3, a4) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4))
#define CALL_5(return_type, call_type, address, a1, a2, a3, a4, a5) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5))
#define CALL_6(return_type, call_type, address, a1, a2, a3, a4, a5, a6) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6))
#define CALL_7(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7))
#define CALL_8(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8))
#define CALL_9(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9))
#define CALL_10(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10))
#define CALL_11(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11))
#define CALL_12(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11),(_dword_)(a12))
#define CALL_13(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11),(_dword_)(a12),(_dword_)(a13))
#define CALL_14(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11),(_dword_)(a12),(_dword_)(a13),(_dword_)(a14))
#define CALL_15(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11),(_dword_)(a12),(_dword_)(a13),(_dword_)(a14),(_dword_)(a15))
#define CALL_16(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11),(_dword_)(a12),(_dword_)(a13),(_dword_)(a14),(_dword_)(a15),(_dword_)(a16))
#define CALL_17(return_type, call_type, address, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) \
((return_type (call_type *)(_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_,_dword_))(address))((_dword_)(a1),(_dword_)(a2),(_dword_)(a3),(_dword_)(a4),(_dword_)(a5),(_dword_)(a6),(_dword_)(a7),(_dword_)(a8),(_dword_)(a9),(_dword_)(a10),(_dword_)(a11),(_dword_)(a12),(_dword_)(a13),(_dword_)(a14),(_dword_)(a15),(_dword_)(a16),(_dword_)(a17))
#define CALL_VA(return_type, adress, a1, ...) \
((return_type (__cdecl *)(_dword_, ...))(adress))((_dword_)(a1), __VA_ARGS__)
// _bool_ - 4-х байтовый логический тип, как BOOL в Win32 API
// если очень захочется, можно заменить на BOOL или однобайтовый bool например
#define _bool_ __int32
// все адреса и часть указателей определены этим типом,
// если вам удобнее по-другому, можете заменить _ptr_ на любой другой тип, void* или int например
typedef _dword_ _ptr_;
// во всех структурах и интерфейсах библиотеки должно быть выравнивание - 4 байта
#pragma pack(push, 4)
//тип "переменная", используется для возвращаемых методами Patcher::VarInit и Patcher::VarFind значений.
class Variable
{
public:
// возвращает значение 'переменной' (потокобезопасное обращение)
virtual _dword_ __stdcall GetValue() = 0;
// устанавливает значение 'переменной' (потокобезопасное обращение)
virtual void __stdcall SetValue(_dword_ value) = 0;
// возвращает указатель на значение (обращение к значению через указатель непотокобезопасно)
virtual _dword_* __stdcall GetPValue() = 0;
};
// тип 'регистр флагов', размер - 32 бита
// используется в HookContext
struct FlagsRegister
{
_dword_ CF : 1; //0
_dword_ reserved_1 : 1; //1
_dword_ PF : 1; //2
_dword_ reserved_3 : 1; //3
_dword_ AF : 1; //4
_dword_ reserved_5 : 1; //5
_dword_ ZF : 1; //6
_dword_ SF : 1; //7
_dword_ TF : 1; //8
_dword_ IF : 1; //9
_dword_ DF : 1; //10
_dword_ OF : 1; //11
_dword_ IOPL : 2; //12-13
_dword_ NT : 1; //14
_dword_ reserved_15 : 1; //15
_dword_ RF : 1; //16
_dword_ VM : 1; //17
_dword_ AC : 1; //18
_dword_ VIF : 1; //19
_dword_ VIP : 1; //20
_dword_ ID : 1; //21
_dword_ reserved_22 : 1; //22
_dword_ reserved_23 : 1; //23
_dword_ reserved_24 : 1; //24
_dword_ reserved_25 : 1; //25
_dword_ reserved_26 : 1; //26
_dword_ reserved_27 : 1; //27
_dword_ reserved_28 : 1; //28
_dword_ reserved_29 : 1; //29
_dword_ reserved_30 : 1; //30
_dword_ reserved_31 : 1; //31
};
// Структура HookContext
// используется в функциях сработавших по LoHook хуку
struct HookContext
{
int eax; //регистр EAX, чтение/изменение
int ecx; //регистр ECX, чтение/изменение
int edx; //регистр EDX, чтение/изменение
int ebx; //регистр EBX, чтение/изменение
int esp; //регистр ESP, чтение/изменение
int ebp; //регистр EBP, чтение/изменение
int esi; //регистр ESI, чтение/изменение
int edi; //регистр EDI, чтение/изменение
_ptr_ return_address; //адрес возврата, чтение/изменение
FlagsRegister flags; //регистр флагов, чтение/изменение
// для языков программирования не поддерживающих битовые поля (напр. delphi)
// flags может быть определен как _dword_ типа.
// функция Push имеет аналогичное действие команде процессора PUSH для контекста LoHook хука
// при использовании с контекстом хука установленного с помощью WriteLoHook или CreateLoHook
// размер памяти которая может быть помещена в стек с помощью этой функции ограничен 128 байтами.
// при использовании с контекстом хука установленного с помощью WriteLoHookEx или CreateLoHookEx
// этот размер устанавливается произвольно при вызове WriteLoHookEx или CreateLoHookEx.
inline void Push(int v)
{
esp -= 4;
*(int*)(esp) = v;
}
// функция Pop имеет аналогичное действие команде процессора POP для контекста LoHook хука
inline int Pop()
{
int r = *(int*)(esp);
esp += 4;
return r;
}
};
// значения возвращаемые функцией срабатываемой по LoHook хуку
#define EXEC_DEFAULT 1
#define NO_EXEC_DEFAULT 0
#define SKIP_DEFAULT 0
// значения возвращаеемые Patch::GetType()
#define PATCH_ 0
#define LOHOOK_ 1
#define HIHOOK_ 2
// значения передаваемые PatcherInstance::Write() и PatcherInstance::CreatePatch()
#define DATA_ 0
#define CODE_ 1
// Абстрактный класс Patch
// создать экземпляр можно с
// помощью методов класса PatcherInstance
class Patch
{
public:
// возвращает адрес по которому устанавливается патч
virtual _ptr_ __stdcall GetAddress() = 0;
// возвращает размер патча
virtual _dword_ __stdcall GetSize() = 0;
// возвращает уникальное имя экземпляра PatcherInstance, с помощью которого был создан патч
virtual char* __stdcall GetOwner() = 0;
// возвращает тип патча
// для не хука всегда PATCH_
// для LoHook всегда LOHOOK_
// для HiHook всегда HIHOOK_
virtual int __stdcall GetType() = 0;
// возвращает true, если патч применен и false, если нет.
virtual _bool_ __stdcall IsApplied() = 0;
// применяет патч
// возвращает >= 0 , если патч/хук применился успешно
// (возвращаемое значение является порядковым номером патча в последовательности
// патчей, примененных по окрестности данного адреса, чем больше число,
// тем позднее был применен патч)
// возвращает -2, если патч уже применен
// Результат выполнения метода распространенно пишется в лог
virtual _bool_ __stdcall Apply() = 0;
// ApplyInsert применяет патч с указанием порядкового номера в
// последовательности патчей, примененных по этому адресу.
// возвращаемые значения аналогичны соответсвующим в Patch::Apply
// функции ApplyInsert можно аргументом передать значение, возвращаемое
// функцией Undo, чтобы применить патч в то же место, на котором тот был до отменения.
virtual _bool_ __stdcall ApplyInsert(int zorder) = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Метод Undo
// Отменяет патч(хук) (в случае если патч применен последним - восстанавливает затертый код)
// Возвращает число >= 0, если патч(хук) был отменен успешно
// (возвращаемое значение является номером патча в последовательности
// патчей, примененных по данному адресу, чем больше число,
// тем позднее был применен патч)
// Возвращает -2, если патч и так уже был отменен (не был применен)
// Результат выполнения метода распространенно пишется в лог
virtual _bool_ __stdcall Undo() = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Метод Destroy
// Деструктор
// Отменяет и безвозвратно уничтожает патч/хук
// возвращает всегда 1 (для совместимости с более ранними версиями библиотеки)
// Результат уничтожения распространенно пишется в лог
virtual _bool_ __stdcall Destroy() = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Метод GetAppliedBefore
// возвращает патч примененный перед данным
// возвращает NULL если данный патч применен первым
virtual Patch* __stdcall GetAppliedBefore() = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Метод GetAppliedAfter
// возвращает патч примененный после данного
// возвращает NULL если данный патч применен последним
virtual Patch* __stdcall GetAppliedAfter() = 0;
};
// Абстрактный класс LoHook (унаследован от Patch, т.е. по сути лоу-хук является патчем)
// создать экземпляр можно с
// помощью методов класса PatcherInstance
class LoHook : public Patch
{
};
typedef int(__stdcall *_LoHookFunc_)(LoHook*, HookContext*);
// значения передаваемые как аргумент hooktype в PatcherInstance::WriteHiHook и PatcherInstance::CreateHiHook
#define CALL_ 0
#define SPLICE_ 1
#define FUNCPTR_ 2
// значения передаваемые как аргумент subtype в PatcherInstance::WriteHiHook и PatcherInstance::CreateHiHook
#define DIRECT_ 0
#define EXTENDED_ 1
#define SAFE_ 2
// значения передаваемые как аргумент calltype в PatcherInstance::WriteHiHook и PatcherInstance::CreateHiHook
#define ANY_ 0
#define STDCALL_ 0
#define THISCALL_ 1
#define FASTCALL_ 2
#define CDECL_ 3
#define FASTCALL_1 1
// Абстрактный класс HiHook (унаследован от Patch, т.е. по сути хай-хук является патчем)
// создать экземпляр можно с помощью методов класса PatcherInstance
class HiHook : public Patch
{
public:
// возвращает указатель на функцию (на мост к функции в случае SPLICE_),
// замещенную хуком
// Внимание! Вызывая функцию для не примененного хука, можно получить
// неактуальное (но рабочее) значение.
virtual _ptr_ __stdcall GetDefaultFunc() = 0;
// возвращает указатель на оригинальную функцию (на мост к функции в случае SPLICE_),
// замещенную хуком(хуками) по данному адресу
// (т.е. возвращает GetDefaultFunc() для первого примененного хука по данному адресу)
// Внимание! Вызывая функцию для не примененного хука, можно получить
// неактуальное (но рабочее) значение.
virtual _ptr_ __stdcall GetOriginalFunc() = 0;
// возвращает адрес возврата в оригинальный код
// можно использовать внутри хук-функции
// SPLICE_ EXTENDED_ или SAFE_ хука, чтобы узнать откуда она была вызвана
// для SPLICE_ DIRECT_ хука функция возвращает всегда 0 (т.е. для DIRECT_ хука возможности узнать адрес возврата через нее - нет)
virtual _ptr_ __stdcall GetReturnAddress() = 0;
//# ver 2.1
// устанавливает значение пользовательских данных хука
virtual void __stdcall SetUserData(_dword_ data) = 0;
// возвращает значение пользовательских данных хука
// если не задано пользователем, то равно 0
virtual _dword_ __stdcall GetUserData() = 0;
};
// Абстрактный класс PatcherInstance
// создать/получить экземпляр можно с помощью методов CreateInstance и GetInstance класса Patcher
// непосредственно позволяет создавать/устанавливать патчи и хуки в код,
// добавляя их в дерево всех патчей/хуков, созданных библиотекой patcher_x86.dll
class PatcherInstance
{
public:
////////////////////////////////////////////////////////////
// Метод WriteByte
// пишет однбайтовое число по адресу address
// (создает и применяет DATA_ патч)
// Возвращает указатель на патч
virtual Patch* __stdcall WriteByte(_ptr_ address, int value) = 0;
////////////////////////////////////////////////////////////
// Метод WriteWord
// пишет двухбайтовое число по адресу address
// (создает и применяет DATA_ патч)
// Возвращает указатель на патч
virtual Patch* __stdcall WriteWord(_ptr_ address, int value) = 0;
////////////////////////////////////////////////////////////
// Метод WriteDword
// пишет четырехбайтовое число по адресу address
// (создает и применяет DATA_ патч)
// Возвращает указатель на патч
virtual Patch* __stdcall WriteDword(_ptr_ address, int value) = 0;
////////////////////////////////////////////////////////////
// Метод WriteJmp
// пишет jmp to опкод по адресу address
// (создает и применяет CODE_ патч)
// Возвращает указатель на патч
// патч закрывает целое количество опкодов,
// т.е. размер патча >= 5, разница заполнятеся NOP'ами.
virtual Patch* __stdcall WriteJmp(_ptr_ address, _ptr_ to) = 0;
////////////////////////////////////////////////////////////
// Метод WriteHexPatch
// пишет по адресу address позледовательность байт,
// определенную hex_str
// (создает и применяет DATA_ патч)
// Возвращает указатель на патч
// hex_str - си-строка может содержать шестнадцатеричные цифры
// 0123456789ABCDEF (только верхний регистр!) остальные символы
// при чтении методом hex_str игнорируются(пропускаются)
// удобно использовать в качестве аргумента этого метода
// скопированное с помощью Binary copy в OllyDbg
/* пример:
pi->WriteHexPatch(0x57b521, "6A 01 6A 00");
*/
virtual Patch* __stdcall WriteHexPatch(_ptr_ address, char* hex_str) = 0;
////////////////////////////////////////////////////////////
// Метод WriteCodePatchVA
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteCodePatch
virtual Patch* __stdcall WriteCodePatchVA(_ptr_ address, char* format, _dword_* va_args) = 0;
////////////////////////////////////////////////////////////
// Метод WriteLoHook
// создает по адресу address низкоуровневый хук (CODE_ патч) и применяет его
// возвращает указатель на хук
// func - функция вызываемая при срабатывании хука
// должна иметь вид int __stdcall func(LoHook* h, HookContext* c);
// в HookContext* c передаются для чтения/изменения
// регистры процессора и адрес возврата
// если func возвращает EXEC_DEFAULT, то
// после завершения func выполняется затертый хуком код.
// если - SKIP_DEFAULT - затертый код не выполняется
//
// ВНИМАНИЕ!
// размер памяти, которая может быть помещена в стек контекста
// с помощью использования c->esp и с->Push, ограничен 128 байтами.
// если требуется иное ограничение используйте метод WriteLoHookEx или CreateLoHookEx.
virtual LoHook* __stdcall WriteLoHook(_ptr_ address, _LoHookFunc_ func) = 0;
////////////////////////////////////////////////////////////
// Метод WriteHiHook
// создает по адресу address высокоуровневый хук и применяет его
// возвращает указатель на хук
//
// new_func - функция замещающая оригинальную
//
// hooktype - тип хука:
// CALL_ - хук НА ВЫЗОВ функции по адресу address
// поддерживаются опкоды E8 и FF 15, в остальных случаях хук не устанавливается
// и в лог пишется информация об этой ошибке
// SPLICE_ - хук непосредственно НА САМУ ФУНКЦИЮ по адресу address
// FUNCPTR_ - хук на функцию в указателе (применяется редко, в основном для хуков в таблицах импорта)
//
// subtype - подтип хука:
// DIRECT_ - new_func имеет тот же вид что и
// оригинальная замещаемая функция
// примечание: вместо __thiscall f(this)
// можно использовать __fastcal f(this_)
// вместо __thiscall f(this, ...) можно использовать
// __fastcall f(this_, no_used_edx, ...)
// EXTENDED_ - функции new_func первым стековым аргументом передается
// указатель на экземпляр HiHook и, в случае
// соглашений исходной ф-ии __thiscall и __fastcall
// регистровые аргументы передаются стековыми вторыми
// Таким образом функция new_func должна иметь вид
// ? __stdcall new_func(HiHook* hook, ?) для ? ? orig(?)
//
// ВНИМАНИЕ! EXTENDED_ FASTCALL_ поддерживает только функции с 2-мя и более аргументами
// для __fastcall c 1 аргументом используйте EXTENDED_ FASTCALL_1 / EXTENDED_ THISCALL_
//
// SAFE_ - то же самое что и EXTENDED_, однако перед вызовом (на время вызова) GetDefaultFunc() восстанавливаются
// значения регистров процессора EAX, ECX (если не FASTCALL_ и не THISCALL_),
// EDX (если не FASTCALL_), EBX, ESI, EDI, бывшие на момент вызова замещенной функции
//
// в подавляющем большинстве случаев удобнее использовать EXTENDED_
// но DIRECT_ выполняется быстрее из-за отсутвия моста к новой замещающей функции
//
// calltype - соглашение о вызове оригинальной замещаемой ф-ии:
// STDCALL_
// THISCALL_
// FASTCALL_
// CDECL_
// необходимо верно указывать соглашение для того чтобы EXTENDED_ хук правильно
// построил мост к новой замещающей функции
//
// CALL_, SPLICE_ хук является CODE_ патчем
// FUNCPTR_ хук является DATA_ патчем
//
virtual HiHook* __stdcall WriteHiHook(_ptr_ address, int hooktype, int subtype, int calltype, void* new_func) = 0;
///////////////////////////////////////////////////////////////////
// Методы Create...
// создают патч/хук так же как и соответствующие методы Write...,
// но НЕ ПРИМЕНЯЮТ его
// возвращают указатель на патч/хук
virtual Patch* __stdcall CreateBytePatch(_ptr_ address, int value) = 0;
virtual Patch* __stdcall CreateWordPatch(_ptr_ address, int value) = 0;
virtual Patch* __stdcall CreateDwordPatch(_ptr_ address, int value) = 0;
virtual Patch* __stdcall CreateJmpPatch(_ptr_ address, _ptr_ to) = 0;
virtual Patch* __stdcall CreateHexPatch(_ptr_ address, char* hex_str) = 0;
virtual Patch* __stdcall CreateCodePatchVA(_ptr_ address, char* format, _dword_* va_args) = 0;
virtual LoHook* __stdcall CreateLoHook(_ptr_ address, void* func) = 0;
virtual HiHook* __stdcall CreateHiHook(_ptr_ address, int hooktype, int subtype, int calltype, void* new_func) = 0;
////////////////////////////////////////////////////////////
// Метод ApplyAll
// применяет все патчи/хуки, созданные этим экземпляром PatcherInstance
// всегда возвращает 1 (для совместимости с более ранними версиями библиотеки)
// (см. Patch::Apply)
virtual _bool_ __stdcall ApplyAll() = 0;
////////////////////////////////////////////////////////////
// Метод UndoAll
// отменяет все патчи/хуки, созданные этим экземпляром PatcherInstance
// т.е. для каждого из патчей/хуков вызывает метод Undo
// всегда возвращает 1 (для совместимости с более ранними версиями библиотеки)
// (см. Patch::Undo)
virtual _bool_ __stdcall UndoAll() = 0;
////////////////////////////////////////////////////////////
// Метод DestroyAll
// отменяет и безвозвратно уничтожает все патчи/хуки, созданные этим экземпляром PatcherInstance
// т.е. для каждого из патчей/хуков вызывает метод Destroy
// всегда возвращает 1 (для совместимости с более ранними версиями библиотеки)
// (см. Patch::Destroy)
virtual _bool_ __stdcall DestroyAll() = 0;
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteDataPatch
virtual Patch* __stdcall WriteDataPatchVA(_ptr_ address, char* format, _dword_* va_args);
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteDataPatch
virtual Patch* __stdcall CreateDataPatchVA(_ptr_ address, char* format, _dword_* va_args);
// Метод GetLastPatchAt
// возвращает NULL, если в окрестности адреса address не был применен ни один патч/хук,
// созданный данным экземпляром PatcherInstance
// иначе возвращает последний примененый патч/хук в окрестности адреса address,
// созданный данным экземпляром PatcherInstance
virtual Patch* __stdcall GetLastPatchAt(_ptr_ address) = 0;
// Метод UndoAllAt
// отменяет патчи примененные данным экземпляром PatcherInstance
// в окрестности адреса address
// всегда возвращает 1 (для совместимости с более ранними версиями библиотеки)
// (см. Patch::Undo)
virtual _bool_ __stdcall UndoAllAt(_ptr_ address) = 0;
// Метод GetFirstPatchAt
// возвращает NULL, если в окрестности адреса address не был применен ни один патч/хук,
// созданный данным экземпляром PatcherInstance
// иначе возвращает первый примененый патч/хук в окрестности адреса address,
// созданный данным экземпляром PatcherInstance
virtual Patch* __stdcall GetFirstPatchAt(_ptr_ address) = 0;
////////////////////////////////////////////////////////////
// Метод Write
// пишет по адресу address данные/код из памяти по адресу data размером size байт
// если is_code == 1, то создается и пишется CODE_ патч, если 0 - DATA_ патч.
// Возвращает указатель на патч
virtual Patch* __stdcall Write(_ptr_ address, _ptr_ data, _dword_ size, _bool_ is_code = 0) = 0;
///////////////////////////////////////////////////////////////////
// Метод CreatePatch
// создаёт патч так же как и метод Write,
// но НЕ ПРИМЕНЯЕТ его
// возвращают указатель на патч
virtual Patch* __stdcall CreatePatch(_ptr_ address, _ptr_ data, _dword_ size, _bool_ is_code = 0) = 0;
//## ver 2.1
////////////////////////////////////////////////////////////
// Метод WriteLoHookEx
// аналогичен методу WriteLoHook, но имеет дополнительный аргумент
// stack_delta - размер памяти который можно поместить в стэк контекста
// используя HookContext::esp и HookContext::Push внутри func.
//
// Возвращают указатель на LoHook хук
virtual LoHook* __stdcall WriteLoHookEx(_ptr_ address, void* func, _dword_ stack_delta) = 0;
// Метод CreateLoHookEx
// создает хук так же как и WriteLoHookEx,
// но НЕ ПРИМЕНЯЕТ его.
// Возвращают указатель на LoHook хук
virtual LoHook* __stdcall CreateLoHookEx(_ptr_ address, void* func, _dword_ stack_delta) = 0;
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteHexHook
virtual LoHook* __stdcall WriteHexHookVA(_ptr_ address, _bool_ exec_default, char* hex_str, _dword_* va_args) = 0;
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки CreateHexHook
virtual LoHook* __stdcall CreateHexHookVA(_ptr_ address, _bool_ exec_default, char* hex_str, _dword_* va_args) = 0;
// метод BlockAt устанавливает блок на определенный адрес (именно на конкретный адрес а не на окрестность)
// для данного экземпляра PatcherInstance
// после чего данный экземпляр PatcherInstance не может применять
// патчи по этому адресу
virtual void __stdcall BlockAt(_ptr_ address) = 0;
//## ver 2.6
// метод BlockAllExceptVA устанавливает блок на все адреса кроме указанных в va_args
// так же как и метод BlockAt оперирует конкретными адресами а не окрестностями
// для данного экземпляра PatcherInstance
// после чего данный экземпляр PatcherInstance не может применять
// патчи по всем адресам кроме указанных.
// список адресов в va_args должен заканчиваться 0 (нулем)
virtual void __stdcall BlockAllExceptVA(_dword_ *va_args) = 0;
//## ver 4.0
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteAsmPatch
virtual Patch* __stdcall WriteAsmPatchVA(_ptr_ address, _dword_* va_args) = 0;
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки CreateAsmPatch
virtual Patch* __stdcall CreateAsmPatchVA(_ptr_ address, _dword_* va_args) = 0;
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteAsmHook
virtual LoHook* __stdcall WriteAsmHookVA(_ptr_ address, _dword_* va_args) = 0;
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки CreateAsmHook
virtual LoHook* __stdcall CreateAsmHookVA(_ptr_ address, _dword_* va_args) = 0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WriteAsmPatch пишет патч по адресу address
// возвращаeт указатель на патч
// аргументы ... - это строки, содержащие код на ассемблере
// распознаются все инструкции, распознаваемые OllyDbg 1.04 (вплоть до MMX и amd 3DNow! включительно)
// ВНИМАНИЕ! в отличие от OllyDbg, целые числа не имеющие префикса 0x или постфикса h читаются как ДЕСЯТЕРИЧНЫЕ!
// поэтому не забывайте писать шеснадцатеричные числа явно
// В одной строке может быть несколько инструкций, разделенных символом ';'
// Код на ассемблере может содержать метки;
// объявление метки - label_name: (имя метки, двоеточие),
// использование label_name (имя без двоеточия);
// максимальная длина имени метки - 39 символов, имя может содержать буквы, цифры, символы '_' и '.';
// код может содержать псевдоинструкцию times (пишет заданное количество раз следующую инструкцию)
// например, результатом "times 3 nop" будет код 90 90 90
// код может содержать псевдоинструкцию _ExecCopy <адрес>, <размер> (пишет код из памяти по адресу <адрес> размером <размер>)
// код может содержать псевдоинструкции db <число>, dw <число>, dd <число или метка>.
// Строка может содержать формат-символы %d. В этом случае за строкой должно следовать соответствующее количество четырехбайтовых чисел (знаковые/беззнаковые/адреса/...)
// ВНИМАНИЕ! последним аргументом (строкой) должен обязательно быть 0 (NULL)!
// абстрактный пример: WriteAsmPatch(0x112233, "begin: call %d", MyFunc, "jmp begin", "jne dword [%d]", 0xAABBCC, 0);
inline Patch* WriteAsmPatch(_ptr_ address, ...)
{
return WriteAsmPatchVA(address, (_dword_*)((_ptr_)&address + 4));
}
////////////////////////////////////////////////////////////
// Метод CreateAsmPatch
// создает патч так же как и метод WriteCodePatch,
// но не применяет его
// возвращаeт указатель на патч
inline Patch* CreateAsmPatch(_ptr_ address, ...)
{
return CreateAsmPatchVA(address, (_dword_*)((_ptr_)&address + 4));
}
////////////////////////////////////////////////////////////
// WriteAsmHook пишет по адресу address примитивный хук
// а именно LoHook без вызова высокоуровневой функции.
// тело хука пишется прямо в вызове CreateHexHook или WriteHexHook
// таким же образом как пишется патч с помощью WriteAsmPatch (см. WriteAsmPatch)
// В отличие метода WriteAsmPatch здесь код может содержать (а может не содержать) псевдокоманду _ExecDefault,
// котроая выполняет затертый хуком код
// ВНИМАНИЕ! в коде не может быть больше одной псевдокоманды _ExecDefault
// возвращает указатель на LoHook хук
// ВНИМАНИЕ! последним аргументом (строкой) должен обязательно быть 0 (NULL)!
// абстрактный пример: WriteAsmHook(0x112233, "cmp eax, 0; jne SkipDefault; _ExecDefault; jmp End; SkipDefault: mov ecx, 2; End: retn", 0);
inline LoHook* WriteAsmHook(_ptr_ address, ...)
{
return WriteAsmHookVA(address, (_dword_*)((_ptr_)&address + 4));
}
////////////////////////////////////////////////////////////
// Метод CreateAsmHook
// создает хук так же как и WriteAsmHook,
// но НЕ ПРИМЕНЯЕТ его.
// Возвращают указатель на LoHook хук
inline LoHook* CreateAsmHook(_ptr_ address, ...)
{
return CreateAsmHookVA(address, (_dword_*)((_ptr_)&address + 4));
}
//WriteHexHook пишет по адресу address самый примитивный хук
//а именно LoHook без вызова высокоуровневой функции.
//тело хука пишется прямо в вызове CreateHexHook или WriteHexHook
//таким же образом как пишется патч с помощью WriteCodePatch (см. WriteCodePatch)
//
//exec_default - выполнять ли затертый хуком код после выполнения тела хука
//возвращает указатель на LoHook хук
inline LoHook* WriteHexHook(_ptr_ address, _bool_ exec_default, char* format, ...)
{
return WriteHexHookVA(address, exec_default, format, (_dword_*)((_ptr_)&format + 4));
}
// Метод CreateHexHook
// создает хук так же как и WriteHexHook,
// но НЕ ПРИМЕНЯЕТ его.
// Возвращают указатель на LoHook хук
inline LoHook* CreateHexHook(_ptr_ address, _bool_ exec_default, char* format, ...)
{
return CreateHexHookVA(address, exec_default, format, (_dword_*)((_ptr_)&format + 4));
}
////////////////////////////////////////////////////////////
// Метод WriteCodePatch
// пишет по адресу address позледовательность байт,
// определенную format и ...
// (создает и применяет CODE_ патч)
// Возвращает указатель на патч
// format - си-строка может содержать шестнадцатеричные цифры
// 0123456789ABCDEF (только верхний регистр!),
// а так же специальные формат-символы (нижний регистр!):
// %b - (byte) пишет однобайтовое число из ...
// %w - (word) пишет двухбайтовое число из ...
// %d - (dword) пишет четырехбайтовое число из ...
// %j - пишет jmp на адрес из ...
// %с - пишет сall ...
// %m - копирует код по адресу ... размером ... (т.е. читает 2 аргумента из ...)
// копирование происходит посредством MemCopyCodeEx (см. описание)
// %% - пишет строку с формат-символами из ...
// %o - (offset) помещает по адресу из аргумента смещение позиции в
// Complex коде, относительно начала Complex кода.
// %n - пишет nop опкоды, количеством равным ... \
#0: - #9: -устанавливает метку (от 0 до 9) к которой можно перейти с помощью #0 - #9 \
#0 - #9 -пишет отностельный адрес после опкодов EB, 70 - 7F, E8, E9, 0F80 - 0F8F
// соответствующей метки; после других опкодов ничего не пишет
// ~b - берет из ... абсолютный адрес и пишет относительное смещение до него
// размером в 1 байт (используется для опкодов EB, 70 - 7F)
// ~d - берет из ... абсолютный адрес и пишет относительное смещение до него
// размером в 4 байта (используется для опкодов E8, E9, 0F 80 - 0F 8F)
// %. - ничего не делает ( как и любой другой не объявленный выше символ после % )
// абстрактный пример:
// Patch* p = pi->WriteCodePatch(address,
// "#0: %%",
// "B9 %d %%", this, // mov ecx, this //
// "BA %d %%", this->context, // mov edx, context //
// "%c %%", func, // call func //
// "83 F8 01 %%", // cmp eax, 1
// "0F 85 #7 %%", // jne long to label 7 (if func returns 0)
// "83 F8 02 %%", // cmp eax, 2
// "0F 85 ~d %%", 0x445544, // jne long to 0x445544 (if func returns 0)
// "EB #0 %%", // jmp short to label 0
// "%m %%", address2, size, // exec code copy from address2
// "#7: FF 25 %d %.", &return_address); // jmp [&return_address]
inline Patch* WriteCodePatch(_ptr_ address, char* format, ...)
{
return WriteCodePatchVA(address, format, (_dword_*)((_ptr_)&format + 4));
}
////////////////////////////////////////////////////////////
// Метод CreateCodePatch
// создает патч так же как и метод WriteCodePatch,
// но не применяет его
// возвращаeт указатель на патч
inline Patch* CreateCodePatch(_ptr_ address, char* format, ...)
{
return CreateCodePatchVA(address, format, (_dword_*)((_ptr_)&format + 4));
}
////////////////////////////////////////////////////////////
// Метод WriteDataPatch
// пишет по адресу address позледовательность байт,
// определенную format и ...
// (создает и применяет DATA_ патч)
// Возвращает указатель на патч
// format - си-строка может содержать шестнадцатеричные цифры
// 0123456789ABCDEF (только верхний регистр!),
// а так же специальные формат-символы (нижний регистр!):
// %b - (byte) пишет однобайтовое число из ...
// %w - (word) пишет двухбайтовое число из ...
// %d - (dword) пишет четырехбайтовое число из ...
// %m - копирует данные по адресу ... размером ... (т.е. читает 2 аргумента из ...)
// %% - пишет строку с формат-символами из ...
// %o - (offset) помещает по адресу из аргумента смещение позиции в
// Complex коде, относительно начала Complex кода.
// %. - ничего не делает ( как и любой другой не объявленный выше символ после % )
// абстрактный пример:
// Patch* p = pi->WriteDataPatch(address,
// "FF FF FF %d %%", var,
// "%m %%", address2, size,
// "AE %.");
inline Patch* WriteDataPatch(_ptr_ address, char* format, ...)
{
return WriteDataPatchVA(address, format, (_dword_*)((_ptr_)&format + 4));
}
////////////////////////////////////////////////////////////
// Метод CreateDataPatch
// создает патч так же как и метод WriteDataPatch,
// но не применяет его
// возвращаeт указатель на патч
inline Patch* CreateDataPatch(_ptr_ address, char* format, ...)
{
return CreateDataPatchVA(address, format, (_dword_*)((_ptr_)&format + 4));
}
inline Patch* __stdcall WriteDword(_ptr_ address, const char* value)
{
return WriteDword(address, (int)value);
}
};
// Класс Patcher
class Patcher
{
public:
// основные методы:
///////////////////////////////////////////////////
// Метод CreateInstance
// создает экземпляр класса PatcherInstance, который
// непосредственно позволяет создавать патчи и хуки и
// возвращает указатель на этот экземпляр.
// owner - уникальное имя экземпляра PatcherInstance
// метод возвращает NULL, если экземпляр с именем owner уже создан
// если owner == NULL или owner == "" то
// экземпляр PatcherInstance будет создан с именем модуля из
// которого была вызвана функция.
virtual PatcherInstance* __stdcall CreateInstance(char* owner) = 0;
///////////////////////////////////////////////////
// Метод GetInstance
// Возвращает указатель на экземпляр PatcherInstance
// с именем owner.
// метод возвращает NULL в случае, если
// экземпляр с именем owner не существует (не был создан)
// в качестве аргумента можно передавать имя модуля.
// Используется для :
// - проверки активен ли некоторый мод, использующий patcher_x86.dll
// - получения доступа ко всем патчам и хукам некоторого мода,
// использующего patcher_x86.dll
virtual PatcherInstance* __stdcall GetInstance(char* owner) = 0;
///////////////////////////////////////////////////
// Метод GetLastPatchAt
// возвращает NULL, если в окрестности адреса address не был применен ни один патч/хук
// иначе возвращает последний примененый патч/хук в окрестности адреса address
// последовательно пройтись по всем патчам в заданной окрестности
// используя этот метод и Patch::GetAppliedBefore
virtual Patch* __stdcall GetLastPatchAt(_ptr_ address);
///////////////////////////////////////////////////
// Метод UndoAllAt
// отменяет все патчи/хуки в окрестности адреса address
// всегда возвращает 1 (для совместимости с более ранними версиями библиотеки)
virtual Patch* __stdcall UndoAllAt(_ptr_ address);
///////////////////////////////////////////////////
// Метод SaveDump
// сохраняет в файл с именем file_name
// - количество и имена всех экземпляров PatcherInstance
// - количество всех примененных патчей/хуков
// - список всех примененных патчей и хуков с их адресами установки, размерами, глобальной очередностью применения, собственниками (именами PatcherInstance)
virtual void __stdcall SaveDump(char* file_name) = 0;
///////////////////////////////////////////////////
// Метод SaveLog
// сохраняет в файл с именем file_name лог
// если логирование выключено в логе будет 0 записей.
// включить логирование можно создав в директории библиотеки
// текстовый файл patcher_x86.ini c cодержимым: Logging = 1
virtual void __stdcall SaveLog(char* file_name) = 0;
///////////////////////////////////////////////////
// Метод GetMaxPatchSize
// Библиотека patcher_x86.dll накладывает некоторые ограничения
// на максимальный размер патча,
// какой - можно узнать с помощью метода GetMaxPatchSize
// (на данный момент это 262144 байт, т.е. дохрена :) )
virtual int __stdcall GetMaxPatchSize() = 0;
// дополнительные методы:
///////////////////////////////////////////////////
// Метод WriteComplexDataVA
// в оригинальном виде применение метода не предполагается,
// смотрите (ниже) описание метода-оболочки WriteComplexString
virtual int __stdcall WriteComplexDataVA(_ptr_ address, char* format, _dword_* args) = 0;
///////////////////////////////////////////////////
// метод GetOpcodeLength
// т.н. дизассемблер длин опкодов
// возвращает длину в байтах опкода по адресу p_opcode
// возвращает 0, если опкод неизвестен
virtual int __stdcall GetOpcodeLength(_ptr_ p_opcode) = 0;
///////////////////////////////////////////////////
// метод MemCopyCode
// копирует код из памяти по адресу src в память по адресу dst
// MemCopyCode копирует всегда целое количество опкодов размером >= size. Будьте внимательны!
// возвращает размер скопированного кода.
// отличается действием от простого копирования памяти тем,
// что корректно копирует опкоды E8 (call), E9 (jmp long), 0F80 - 0F8F (j** long)
// c относительной адресацией не сбивая в них адреса, если инструкции
// направляют за пределы копируемого блокая.
//
virtual int __stdcall MemCopyCode(_ptr_ dst, _ptr_ src, _dword_ size) = 0;
///////////////////////////////////////////////////
// Метод GetFirstPatchAt
// возвращает NULL, если в окрестности адреса address не был применен ни один патч/хук
// иначе возвращает первый примененый патч/хук в окрестности адреса address
// последовательно пройтись по всем патчам в заданной окрестности
// используя этот метод и Patch::GetAppliedAfter
virtual Patch* __stdcall GetFirstPatchAt(_ptr_ address);
///////////////////////////////////////////////////
// метод MemCopyCodeEx
// копирует код из памяти по адресу src в память по адресу dst
// возвращает размер скопированного кода.
// отличается от MemCopyCode тем,
// что корректно копирует опкоды EB (jmp short), 70 - 7F (j** short)
// c относительной адресацией не сбивая в них адреса, если инструкции
// направляют за пределы копируемого блокая (в этом случае они заменяются на
// соответствующие E9 (jmp long), 0F80 - 0F8F (j** long) опкоды.
// Внимание! Из-за этого размер скопированного кода может оказаться значительно
// больше копируемого.
virtual int __stdcall MemCopyCodeEx(_ptr_ dst, _ptr_ src, _dword_ size) = 0;
// ver 2.3
// Метод VarInit
// инициализирует "переменную" c именем name и устанавливает значение "переменной" равным value
// если "переменная" с таким именем уже существует, то просто устанавливает ее значение равным value
// возвращает указатель на "переменную" в случае успеха и NULL в противном случае
virtual Variable* __stdcall VarInit(char* name, _dword_ value) = 0;
// Метод VarFind
// возвращает указатель на "переменную" с именем name, если такая была инициализированна
// если нет, возвращает NULL
virtual Variable* __stdcall VarFind(char* name) = 0;
// ver 2.6
// Метод PreCreateInstance
// Создает неполноценный экземпляр PatcherInstance с указанным именем.
// PatcherInstance созданный таким образом не может создавать патчи.
// Этот неполноценный экземпляр используется для применения методов PatcherInstance::BlockAt и PatcherInstance::BlockAllExceptVA
// чтобы можно было заблокировать адреса до того как данный PatcherInstance будет полноценно создан с помощью CreateInstance
virtual PatcherInstance* __stdcall PreCreateInstance(char* name) = 0;
// ver 4.1
// описание в разработке...
virtual int __stdcall WriteAsmCodeVA(_ptr_ address, _dword_* args) = 0;
virtual _ptr_ __stdcall CreateCodeBlockVA(_dword_* args) = 0;
// метод VarGetValue возвращает значение "переменной" c именем name
// если "переменная" с таким именем не была инициализированна, возвращает default_value
template<typename ValueType>
inline ValueType VarGetValue(char* name, ValueType default_value)
{
if (sizeof(ValueType) > 4) return default_value;
Variable* v = VarFind(name);
if (v == NULL) return default_value;
return (ValueType)v->GetValue();
}
// метод VarValue возвращает ссылку на значение "переменной" c именем name
// если "переменная" с таким именем не была инициализированна, инициализирует ее и устанавливает значение равным 0
// внимание, обращение к значению переменной по ссылке непотокобезопасно
template<typename ValueType>
inline ValueType& VarValue(char* name)
{
if (sizeof(ValueType) > 4) __asm{__asm int 3};
Variable* v = VarFind(name);
if (v == NULL) v = VarInit(name, 0);
if (v == NULL) __asm{__asm int 3};
return (ValueType&)*v->GetPValue();
}
////////////////////////////////////////////////////////////////////
// метод WriteComplexData
// является более удобным интерфейсом
// метода WriteComplexDataVA
// этот метод определен здесь а не в библиотеке, т.к. его вид
// отличается в Си и Делфи
// Функционал метода почти тот же что и у PatcherInstance::WriteCodePatch
// (см. описание этого метода)
// то есть метод пишет по адресу address, последовательность байт,
// определенную аргументами format и ...,
// НО! НЕ создает экземпляр класса Patch, со всеми вытекающими (т.е. не позволяя отменить правку, получить доступ к правке из другого мода и т.д.)
// ВНИМАНИЕ!
// Используйте этот метод только для динамического создания блоков
// кода, т.е. пишите этим методом только в свою память,
// а в код модифицируемой программы только с помощью
// PatcherInstance::WriteCodePatch
//
inline _ptr_ WriteComplexData(_ptr_ address, char* format, ...)
{
return WriteComplexDataVA(address, format, (_dword_*)((_ptr_)&format + 4));
}
inline HiHook* GetFirstHiHookAt(_ptr_ address)
{
Patch* p = GetFirstPatchAt(address);
while (true)
{
if (p == 0) return 0;
if (p->GetType() == HIHOOK_) return (HiHook*)p;
p = p->GetAppliedAfter();
}
}
inline HiHook* GetLastHiHookAt(_ptr_ address)
{
Patch* p = GetLastPatchAt(address);
while (true)
{
if (p == 0) return 0;
if (p->GetType() == HIHOOK_) return (HiHook*)p;
p = p->GetAppliedBefore();
}
}
};
// восстанавливаем выравнивание членов структур и классов
#pragma pack(pop)
//////////////////////////////////////////////////////////////////
//функция GetPatcher
//загружает библиотеку и, с помощью вызова единственной экспортируемой
//функции _GetPatcherX86@0, возвращает указатель на объект Patcher,
//посредством которого доступен весь функционал библиотеки patcher_x86.dll
//возвращает NULL при неудаче
//функцию вызывать 1 раз, что очевидно из ее определения
#include <windows.h>
inline Patcher* GetPatcher()
{
static int calls_count = 0;
if (calls_count > 0) return NULL;
calls_count++;
HMODULE pl = LoadLibraryA("patcher_x86.dll");
if (pl)
{
FARPROC f = GetProcAddress(pl, "_GetPatcherX86@0");
if (f) return CALL_0(Patcher*, __stdcall, f);
}
return NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment