Gratt
Модостроитель
- Регистрация
- 14 Ноя 2014
- Сообщения
- 3.301
- Благодарности
- 4.641
- Баллы
- 625
Русский English
Общее описание формата патчей
Рекомендуется использовать Notepad++ для редактирования файлов патчей, а также установить расширение для подсветки синтаксиса из Менеджера ресурсов в разделе 'Синтаксис .patch'. Желательно использовать только кодировки ANSI, либо UTF8 с BOM и Unicode с BOM. Остальные могут привести к неожиданным последствиям. Приоритет запуска определяется нижним подчеркиванием вначале имени файла. Чем больше подчеркиваний, тем выше приоритет. Если подчеркивания отсутствуют, то вначале запускается Union.patch, затем все остальные.
Union:/* * Union PATCH * ----------- * Файл патчей - это скрипт, позволяющий изменять любые участки * памяти процесса. Не требует предварительной компиляции, а * все .patch файлы, лежащие в директориях игры или VDF томах, * будут запущены игрой автоматически. Скрипт является * регистронезависимым, на каждый блок операторов выделяется * по одной строке. * * Ниже приведен краткий пример типичного файла * патчей и комментарии для каждой инструкции. */ // Инструкция #disable [<PATCH NAME>] служит для запрета выполнения патчей. // Она имеет наивысший приоритет. Это значит, что в каком бы файле // не находились перечисленные патчи - они однозначно будут отключены. #disable [Reference] #disable [Cast] // Процедуры патчей выполняются внутри блоков #engine [<ENGINE>]. // Это блоки, которые выполняются при запуске конкретных ехе файлов. // В качестве ехе могут указываться как crc32 от exe файла, // так и теги (G1, G1A, G2, G2A). Для выполнения патчей под несколько // платформ, следует перечислить их через запятую. Либо не указывать // аргументы вообще, тогда блок будет выполнен не зависимо от ехе. // Таких блоков #engine может быть несколько на один файл. #engine [0x2BCD7E30, G2A] // crc32, tag // В роли процедуры патча выступает блок #patch [<NAME>]. // Все блоки патча выполняются автоматически поочереди. // Каждый блок патча может иметь собственный набор локальных переменных, // однако если блок называется `GLOBAL DATA`, то переменные внутри него // могут использоваться Глобально - всеми остальными блоками патчей. #patch [GLOBAL DATA] // Внутри блоков патчей могут объявляться и использоваться любые // описываемые далее типы. По умолчанию патчи имеют 4 базовых типа: // INT - целое, ассоциируется с 12345, 0x12345 // FLOAT - вещественное, ассоциируется с 123.45 // BOOL - логическое, ассоциируется с True, False // HEX - строка/байткод, ассоциируется с "12345", '12 34 05' // // На последнем типе остановимся подробнее. Этот тип может использоваться // и как строка, так и обычный массив байтов. При этом размерность такой // переменной можно вычислить функцией GetHexSize, либо задать через SetHexSize. // или SetHexAutoSize. Оператор HEX + HEX будет работать по принципу сложения // строк. Использование одинарной кавычки (') расценивается патчем как // последовательность байтов, разделенных пробелом. INT GlobalInteger = 100 FLOAT GlobalFloat = 200.0 HEX GlobalHex = "300" + "400" BOOL GlobalDeclaration #/patch #patch [Reference] // Помимо обычных типов также существуют ссылочные типы. Это такие типы, // память который определена не программой патча, а некоторой областью в // процессе. Особенностью таких ссылок является не только то, что через // них можно присваивать значения в любую область памяти процесса, но и то, // что они самостоятельно занимаются разблокировкой защищенной от записи памяти. // В отличии от переменных, ссылочные переменные обязаны быть определены конкретным адресом. // Для этого после указания типа ссылки следует добавить символ @. // В качестве адреса указывается целое число. INT @IntegerRef = 0x12345678 + GlobalInteger HEX @HexRef = 0x87654321 // После определения ссылки, она может принимать участие в выражениях, а // ее значение будет строго привязано к адресу, которым она была определена. IntegerRef = GlobalIntegerRef + 800 HexRef = '12 34 56 78 9A BC' // Также при необходимости можно напрямую работать со ссылками не создавая никакие // переменные. Для этого вместо уникального идентификатора указывается либо // число, либо INT переменная с адресом. Будьте осторожны используя переменную // в качестве адреса такой ссылки, ведь синтаксически это идентично определению // ссылочной переменной (в отладочную консоль будет выведено предупреждение). FLOAT @0x12345678 = 50.5 FLOAT @(0x12345678 + 400) = 35.3 FLOAT @GlobalInteger = 10.1 // Не переменная! GlobalInteger – это INT переменная из // блока GLOBAL DATA, которая определяет адрес ссылки! // Ссылки могут не только определять какую-то область памяти, но и параметры // INI файлов. Для этого вместо адреса следует указать файл:блок:параметр. // В качестве файла можно указывать SystemPack, Game (Gothic.ini), Mod (<Mod>.ini) // и Overrides_SP. Последний позволяет переопределять значения SystemPack, не // трогая его физическую подлинник, но имея над ним больший приоритет. INT @SystemPack:Core:ShowDebugWindow = true #/patch #patch [Cast] // Приведения типов в патчах может быть как автоматическим, так и явным. // Автоматическое приведение типов означает, что в выражении тип правого операнда // будет приведен к типу левого операнда. Чтобы произвести явное приведение типов, // укажите имя этого типа перед операндом. INT Value = 5 FLOAT AutoCast = 10.0 + Value * 5.3 // = 35.0 – потеря данных, так как INT * FLOAT преобразуется в INT * INT FLOAT ExplicitCast = 10.0 + FLOAT Value * 5.3 // = 36.5 – точность не страдает, так как FLOAT INT * FLOAT преобразуется во FLOAT * FLOAT // Приведение к HEX и обратно работает иначе. HEX как бы снимает тип с объекта, // преобразуя его в набор байтов. По этому принципу работает и обратная операция, // когда набор байтов приводится к какому-то типу. INT SourceInt = 65535 HEX CastedHex = HEX SourceInt // = '00 00 FF FF', размер данных 4 байта INT RestoredInt = INT CastedHex // = 65535 #/patch #patch [Operetor IF] // Патчи поддерживают условные блоки IF. Передаваемое в них выражение должно // приводиться к BOOL. Если значение равно True, то блок будет выполнен. // Иначе - пропущен, а при наличии блока ELSE - будет выполнен последний. IF BOOL @SystemPack:Core:ShowDebugWindow != true MessageBox("Debug window disabled") ELSE MessageBox("Debug window enabled") // sub if IF INT @0x12345678 > 500 MessageBox("Block works") END END #/patch #patch [Memory pages] // Иногда патчам требуется достаточное место в памяти для занесения туда каких-либо // байткодов, либо для хранения информации. В этом случае средствами патчей можно // выделять страницы памяти с доступом для чтения, записи и выполнения. Используйте // функцию AllocPage(INT index, INT size) для выделения страницы с индексом index // (любой свободный, но не меньше 1) и размером size. AllocPage(15, 1024) // Для обращения к странице используйте шестнадцатеричный формат записи адреса, где вместо // `0x` указывается индекс выделенной страницы в десятичном формате. Тогда адрес будет рассчитываться как // <адрес страницы> + <смещение> HEX @pageStart = 15x00000000 // Создание ссылки, адрес которой соответствует началу 15-ой страницы памяти HEX @pageRandom = 15x00000111 // Создание ссылки, адрес которой соответствует началу 15-ой страницы памяти + 0x111 байтов #/patch #patch static [Keyword 'static'] // Ключевое слово static применяется, когда необходимо оптимизировать загрузку // патчей, не имеющих условных операторов или динамических операций. Патч, // содержащий исключительно байткод, отлично подходит для такой цели. Union // записывает всю изменяемую статическими патчами память и сохраняет на диск // одним большим куском. При следующем запуске, если патч не изменялся, // бинарные данные сразу же будут помещены в память, а скриптовые блоки // статических патчей - исключены из синтаксического разбора. HEX @0x007524A6 = 'E9 EB C2 F1 FF' HEX @0x0066E796 = '8B 0D 50 16 8D 00 8B 11 6A 05 FF 52 04 3C 01 0F 85 73 40 0E 00 E8 E8 47 16 00 E9 F6 3C 0E 00' // Если патч выполняется из VDF тома, то для него не будет создаваться файл со // статической памятью, однако он может быть прочитан, если такой файл был // создан заранее и помещен рядом с исходным патчем. #/patch #/engine /* * Список встроенных функций */ // Возвращает квадратный корень value числа INT or FLOAT Sqrt(INT or FLOAT value) // Выводит на экран сообщение со строкой // из перечисленных args аргументов VOID MessageBox(args ...) // Выводит в консоль сообщение со строкой // из перечисленных args аргументов VOID PrintScreen(args ...) // Выделяет страницу памяти с индексом index // (любой уникальный, но не меньше 1) и размером // size байтов. VOID AllocPage(INT index, INT size) // освобождает страницу памяти с индексом index VOID FreePage(INT index) // Возвращает используемый размер памяти HEX объекта INT GetHexSize(HEX value) // Задает используемый размер памяти HEX объекта VOID SetHexSize(HEX value, INT size) // Автоматически задает используемый размер памяти // HEX объекта, выравнивая его как строку по символу \0 VOID SetHexAutoSize(HEX value) // Загружает в память библиотеку libName INT LoadLibrary(HEX libName) // Возвращает базовый адрес модуля moduleName, иначе -1 INT ModuleBase(HEX moduleName) // Возвращает минимальное из двух значений value1 и value2 INT or FLOAT Min(INT or FLOAT value1, INT or FLOAT value2) // Возвращает максимальное из двух значений value1 и value2 INT or FLOAT Max(INT or FLOAT value1, INT or FLOAT value2) // Возвращает значение currentValue, но не // меньше minValue и не больше maxValue INT or FLOAT Lim(INT or FLOAT minValue, INT or FLOAT currentValue, INT or FLOAT maxValue) // Выводит на экран сообщение, в котором находится последовательность // из size байтов объекта bytePtr. При отсутствии аргумента size // длина строки будет взята автоматически по размеру объекта bytePtr. VOID HexViewBox(HEX bytePtr, INT size = auto) // Находит и заменяет from последовательность байтов на to // последовательность байтов, начиная со startAddress длиною length VOID FindAndReplace(HEX from, HEX to, INT startAddress, INT length) // Создаем ключ iniParameterRef в ini файле, если до этого // он не был создан и присваивает ему начальное значение value VOID OptionDef(INT or FLOAT or BOOL or HEX iniParameterRef, INT or FLOAT or BOOL or HEX value) // Возвращает размер модуля moduleName, иначе -1 INT ModuleSize(HEX moduleName) // Создает консольное окно VOID ShowCmd() // Уничтожает консольное окно VOID HideCmd() // Возвращает адрес символа symName из // модуля moduleName, иначе -1 INT ImportSymbol(HEX moduleName, HEX symName) // Заполняет память со startAddress // по шаблону bytePtr длиною length VOID MemSet(INT startAddress, HEX bytePtr, INT length) // Копирует память начиная со startAddress // в placeAddress длиною length VOID MemCopy(INT startAddress, INT placeAddress, INT length) // Возвращает хендлер окна windowName класса className INT FindWindowHandle(HEX className, HEX windowName) // Загружает плагины pluginNames, перечисленные через запятую // и возвращает количество успешных загрузок INT LoadPlugins(HEX pluginNames) // Возвращает версию Union в текстовом формате HEX GetUnionVersion() // Переименовывает файле oldName в newName VOID RenameFile(HEX oldName, HEX newName) // Копирует файл oldName в newName с условием замены replace (по умолчанию rue) VOID CopyFile(HEX oldName, HEX newName, BOOL replace = true) // Перемещает файл oldName в newName VOID MoveFile(HEX oldName, HEX newName) // Удаляет файл fileName VOID DeleteFile(HEX fileName) // Проверяет, существует ли файл fileName BOOL FileExists(HEX fileName) // Выводит в консоль списов всех патч-функций VOID ShowFunctionList() // Возвращает путь к директории Steam HEX FindSteamDirectory() // Возвращает ID процесса с именем procName INT GetProcessID(HEX procName) // Создает новый процесс procName и командной строкой cmdLine // и возвращает ID созданного процесса, иначе -1 INT StartProcess(HEX procName, HEX cmdLine) // Соединяет все переданные в функцию аргументы args // в текстовую строку и возвращает ее HEX Concat(agrs ...) // Возвращает текущее разрешение экрана по X INT GetScreenSizeX() // Возвращает текущее разрешение экрана по Y INT GetScreenSizeY() // Перезагружает игру VOID Restart() // Создает инструкцию перехода по адресу addressFrom на память memTo // Заменяет 5 байт по адресу addressFrom VOID JMP(INT addressFrom, HEX memTo) // Создает инструкцию вызова по адресу addressFrom на память memTo // Заменяет 5 байт по адресу addressFrom VOID CALL(INT addressFrom, HEX memTo) // Возвращает язык используемый в Union // Rus = 1, Eng = 2, Deu = 3, Pol = 4 // Rou = 5, Ita = 6, Cze = 7, Esp = 8 INT GetLanguage() // Возвращает адрес ссылки reference INT GetRefAddress(HEX or INT or FLOAT reference) // Выполняет код ассемблерной вставки code (эквивалент API вызова) // Возвращает результат процедуры INT ExecAsm(HEX code)
General description of the PATCH format
It is recommended to use Notepad ++ to edit patch files, and also install the syntax highlighting extension from the Resource manager under the 'Syntax .patch' section. It is advisable to use only ANSI encodings, or UNT8 with BOM and Unicode with BOM. The rest can lead to unexpected consequences. The startup priority is defined by the underscore at the prefix of the file name. The more underscores, the higher the priority. If there are no underscores, then Union.patch is run first, then all the others.
Union:/* * Union PATCH * ----------- * The patch file is a script that allows you to change any areas * process memory. Does not require pre-compilation, but * all .patch files located in game directories or VDF volumes, * will be launched by the game automatically. The script is * case-insensitive, for each block of operators allocated * one line at a time. * * Below is a short example of a typical file * patches and comments for each instruction. */ // The #disable [<PATCH NAME>] instruction is used to disable the execution of patches. // It has the highest priority. This means that in whatever file // the listed patches were found - they will definitely be disabled. #disable [Reference] #disable [Cast] // Patch routines are executed inside #engine [<ENGINE>] blocks. // These are the blocks that are executed when specific exe files are run. // exe can be specified as crc32 from exe file, // and tags (G1, G1A, G2, G2A). To perform patches for multiple // platforms, separate them with commas. Or do not specify // arguments in general, then the block will be executed regardless of exe. // There can be several such #engine blocks per file. // The #patch [<NAME>] block works as a patch procedure. // All patch blocks are executed automatically one by one. // Each block can have its own set of local variables, // however, if the block is called `GLOBAL DATA`, then the variables inside it // can be used Globally - by all other patch blocks. #patch [GLOBAL DATA] // Any patch can be declared and used inside patch blocks. // types described below. By default, patches are of 4 basic types: // INT is an integer associated with 12345, 0x12345 // FLOAT - real, associated with 123.45 // BOOL - boolean, associated with True, False // HEX - string / bytecode, associated with "12345", '12 34 05 ' // // Let's get deeper on the last type in more detail. This type can be used // both a string and a regular byte array. Moreover, the dimension is // variable can be calculated using the GetHexSize function, or set via SetHexSize. // or SetHexAutoSize. The HEX + HEX operator will work on the principle of addition // lines. The use of a single quote (') is interpreted by the patch as // a sequence of bytes separated by a space. INT GlobalInteger = 100 FLOAT GlobalFloat = 200.0 HEX GlobalHex = "300" + "400" BOOL GlobalDeclaration #/patch #patch [Reference] // Besides regular types, there are also reference types. These are the types // memory which is not defined by the patch program, but by some area in // process. The peculiarity of such links is not only that through // they can be assigned values to any area of the process memory, but even then // that they are unlocking the write-protected memory on their own. // Unlike variables, reference variables must be defined with a specific address. // To do this, add the @ symbol after specifying the link type. // An integer is specified as the address. INT @IntegerRef = 0x12345678 + GlobalInteger HEX @HexRef = 0x87654321 // After defining the link, it can take part in expressions, and // its value will be strictly linked to the address it was defined by. IntegerRef = GlobalIntegerRef + 800 HexRef = '12 34 56 78 9A BC' // a reference variable (a warning will be displayed in the debug console). // Also, if necessary, you can directly work with links without creating any // variables. To do this, instead of a unique identifier, either // number, or INT variable with address. Be careful when using a variable // as the address of such a link, because syntactically this is identical to the definition // a reference variable (a warning will be displayed in the debug console). FLOAT @0x12345678 = 50.5 FLOAT @(0x12345678 + 400) = 35.3 FLOAT @GlobalInteger = 10.1 // Not a variable! GlobalInteger is an INT variable from // GLOBAL DATA block, which defines the link address! // Links can not only define some memory area, but also parameters // INI files. To do this, instead of the address, you should specify the file: block: parameter. // SystemPack, Game (Gothic.ini), Mod (<Mod> .ini) and Overrides_SP. can be specified as a file. // The latter allows you to override the SystemPack values without editing its original object, // but having higher priority over it. INT @SystemPack:Core:ShowDebugWindow = true #/patch #patch [Cast] // Type casts in patches can be either automatic or explicit. // Automatic type casting means that the type of the right operand in the expression // will be cast to the type of the left operand. To make an explicit cast, // put the name of this type before the operand. INT Value = 5 FLOAT AutoCast = 10.0 + Value * 5.3 // = 35.0 - data loss, as INT * FLOAT is converted to INT * INT FLOAT ExplicitCast = 10.0 + FLOAT Value * 5.3 // = 36.5 - accuracy does not suffer, since FLOAT INT * FLOAT is converted to FLOAT * FLOAT // Casting to HEX and back works differently. HEX, as it were, removes the type from the object, // converting it to a set of bytes. The reverse operation works according to this principle, // when a set of bytes is cast to some type. INT SourceInt = 65535 HEX CastedHex = HEX SourceInt // = '00 00 FF FF', data size 4 bytes INT RestoredInt = INT CastedHex // = 65535 #/patch #patch [Operetor IF] // Patches support conditional IF blocks. The expression passed to them must // cast to BOOL. If the value is True, then the block will be executed. // Otherwise - skipped, and if there is an ELSE block, the last one will be executed. IF BOOL @SystemPack:Core:ShowDebugWindow != true MessageBox("Debug window disabled") ELSE MessageBox("Debug window enabled") // sub if IF INT @0x12345678 > 500 MessageBox("Block works") END END #/patch #patch [Memory pages] // Sometimes patches need enough space in memory to store any // bytecodes, or for storing information. In this case, using patches you can // allocate memory pages with read, write and execute access. Use // function AllocPage (INT index, INT size) to allocate the page with the index index // (any free, but not less than 1) and size. AllocPage(15, 1024) // To refer to the page, use the hexadecimal address format, where instead of // `0x` indicates the index of the selected page in decimal format. Then the address will be calculated as // <page address> + <offset> HEX @pageStart = 15x00000000 // Create a link, the address of which corresponds to the beginning of the 15th memory page HEX @pageRandom = 15x00000111 // Create a link whose address corresponds to the beginning of the 15th page of memory + 0x111 bytes #/patch #patch static [Keyword 'static'] // The static keyword is used when it is necessary to optimize loading // patches that have no conditional statements or dynamic operations. Patch, // containing only bytecode is great for this purpose. Union // writes all static patched memory and saves it to disk // in one big piece. At the next start, if the patch has not changed, // binary data will be immediately put into memory, and static blocks // patches - excluded from parsing. HEX @ 0x007524A6 = 'E9 EB C2 F1 FF' HEX @ 0x0066E796 = '8B 0D 50 16 8D 00 8B 11 6A 05 FF 52 04 3C 01 0F 85 73 40 0E 00 E8 E8 47 16 00 E9 F6 3C 0E 00' // If the patch is executed from a VDF volume, a file for such patch // will not be created with static memory, however it can be read if // such a file was pre-created and placed next to the original patch. #/patch #/engine /* * A list of built-in functions */ // Returns the square root of value of a number INT or FLOAT Sqrt(INT or FLOAT value) // Displays a message with a string // from the listed args arguments VOID MessageBox(args ...) // Print a message to the console with the string // from the listed args arguments VOID PrintScreen(args ...) // Allocates memory page with index index // (any unique, but not less than 1) and size bytes VOID AllocPage(INT index, INT size) // frees the memory page at index index VOID FreePage (INT index) // Returns the used memory size of the HEX object INT GetHexSize (HEX value) // Sets the used memory size of the HEX object VOID SetHexSize (HEX value, INT size) // Automatically sets the used memory size // HEX of the object, aligning it as a string at the \ 0 character VOID SetHexAutoSize (HEX value) // Loads the libName library into memory INT LoadLibrary (HEX libName) // Returns the base address of the module moduleName, otherwise -1 INT ModuleBase (HEX moduleName) // Returns the minimum of the two values value1 and value2 INT or FLOAT Min (INT or FLOAT value1, INT or FLOAT value2) // Returns the maximum of the two values value1 and value2 INT or FLOAT Max (INT or FLOAT value1, INT or FLOAT value2) // Returns currentValue, but not // less than minValue and not more than maxValue INT or FLOAT Lim (INT or FLOAT minValue, INT or FLOAT currentValue, INT or FLOAT maxValue) // Displays a message containing the sequence // from size bytes of object bytePtr. With no size argument // the string length will be taken automatically according to the size of the bytePtr object. VOID HexViewBox (HEX bytePtr, INT size = auto) // Finds and replaces from byte sequence with to // sequence of bytes starting at startAddress and length VOID FindAndReplace (HEX from, HEX to, INT startAddress, INT length) // Create iniParameterRef key in ini file, if before // it was not created and assigns an initial value to it VOID OptionDef (INT or FLOAT or BOOL or HEX iniParameterRef, INT or FLOAT or BOOL or HEX value) // Returns the size of the module moduleName, otherwise -1 INT ModuleSize (HEX moduleName) // Creates a console window VOID ShowCmd () // Destroys the console window VOID HideCmd () // Returns the address of the symbol symName from // module moduleName, otherwise -1 INT ImportSymbol (HEX moduleName, HEX symName) // Fill memory with startAddress // bytePtr template with length length VOID MemSet (INT startAddress, HEX bytePtr, INT length) // Copies memory starting at startAddress // in placeAddress with length VOID MemCopy (INT startAddress, INT placeAddress, INT length) // Returns the window handler windowName class className INT FindWindowHandle (HEX className, HEX windowName) // Loads plugins pluginNames, separated by commas // and returns the number of successful downloads INT LoadPlugins (HEX pluginNames) // Returns the text version of Union HEX GetUnionVersion () // Renames file oldName to newName VOID RenameFile (HEX oldName, HEX newName) // Copies file oldName to newName with replace condition (rue by default) VOID CopyFile (HEX oldName, HEX newName, BOOL replace = true) // Move file oldName to newName VOID MoveFile (HEX oldName, HEX newName) // Delete file fileName VOID DeleteFile (HEX fileName) // Checks if file fileName exists BOOL FileExists (HEX fileName) // Prints all patch functions to the console VOID ShowFunctionList () // Returns the path to the Steam directory HEX FindSteamDirectory () // Returns the ID of the process named procName INT GetProcessID(HEX procName) // Creates a new process procName and command line cmdLine // and returns the ID of the created process, otherwise -1 INT StartProcess(HEX procName, HEX cmdLine) // Concatenates all args passed to the function // into a text string and returns it HEX Concat(agrs ...) // Returns the current screen resolution in X INT GetScreenSizeX() // Returns the current screen resolution in Y INT GetScreenSizeY() // Restarts the game VOID Restart() // Creates a jump instruction at 'addressFrom' to 'memTo' memory // Replaces 5 bytes at 'addressFrom' VOID JMP(INT addressFrom, HEX memTo) // Creates a call instruction at 'addressFrom' on 'memTo' memory // Replaces 5 bytes at 'addressFrom' VOID CALL(INT addressFrom, HEX memTo) // Returns the language used in Union // Rus = 1, Eng = 2, Deu = 3, Pol = 4 // Rou = 5, Ita = 6, Cze = 7, Esp = 8 INT GetLanguage() // Returns the address of the 'reference' INT GetRefAddress(HEX or INT or FLOAT reference)
Последнее редактирование: