ВНИМАНИЕ! для того, чтобы Ваши патчи работали под ART, нельзя полностью убирать прыжки или делать их безусловными, так как в этом случае остается код, в который оптимизатор не может попасть (висящий код), и он падает с критической ошибкой при оптимизации. Чтобы этого избежать, необходимо заменять прыжки условными переходами, которые всегда срабатывают. К примеру, если Вам нужно обязательно прыгнуть в каком-то месте, то замените прыжок там на if-eq v0,v0 (в байтах это 32 00 ?? ??). Если же Вам не надо прыгать в каком-то месте,то можно там поставить прыжок if-ne v0,v0 (в байтах это 33 00 ?? ??) или сами посмотрите каким эквивалентом заменить можно.

1. Текстовый файл надо называть также как и пакейдж программы... К примеру для Titanium Backup нужно создать такое имя файла: com.keramidas.TitaniumBackup.txt (обязательно соблюдать заглавные и строчные буквы из названия пакейджа, иначе не найдет (linux - мать его)). Если файл пользовательского патча для приложения уже существует, вы можете просто добавить в начале имени файла любой текст и сохранить его рядом с существующим. В этом случае, при выборе в приложении "Пользовательский патч", Lucky Patcher предложит Вам список пользовательских патчей для приложения на выбор. Если Вы хотите написать патч сразу на целую серию программ одной фирмы, то в конце названия файла пользовательского патча, можно использовать идентификатор _%25ALL%25 , к примеру название патча для всех голосов SVOX будет выглядеть так: com.svox.classic.langpack_%25ALL%25.txt. На _%25ALL%25 заменяется часть в названии пакета, которая меняется в зависимости от приложения данной фирмы. Если еще необходимо добавить вначала названия файла своё имя, к примеру, то можно воспользоваться %25ALL%25_ и _%25ALL%25. (Пример:chelpus.%25ALL%25_com.android._%25ALL%25.txt). При выводе имен пользовательских патчей в самой программе %25ALL%25_ скрывается для простоты восприятия. В самом тексте пользовательского патча можно использовать %25PACKAGE_NAME%25, вместо которого во время патча будет подставлено имя пакета приложения цели. Это полезно в патчах для группы приложений, где путь к файлу будет меняться в зависимости от имени пакета (Пример:/data/data/%25PACKAGE_NAME%25/files/trial.txt).

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

[BEGIN]
Этот пользовательский патч добавляет розочку в зубы Keramidas. ver.4.4.4
[PACKAGE]
[CLASSES]
{"search":"15 01 00 30 ** 20 ** ** 31 ** 20 ** ** ** ** R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 12 ** R11 R12 R13 0E 00"}
{"search":"10 ** ** ** ** 0C 01 1A 04 R14 R15 1A 05 00 00 72 30 ** ** ** ** 0C 04"}
{"search":"0C 01 1A 03 ** ** 72 30 R16 ** ** ** 72 10"}
 
{"group":"1"}
{"original":"12 ** 22 00 ** 04 ** W0 ** W2 ** W3 22 02 ** 04"}
{"replaced":"** S1 ** ** ** ** W16 ** W16 ** W16 ** ** ** ** **"}
 
{"group":"1"}
{"original":"0c 07 ** ** ** ** ** ** 38 ** ** ** 70"}
{"replaced":"** ** ** ** ** ** ** ** W11 W11 W11 W11 **"}
 
{"original":"12 ** 12 ** 6a ** ** ** 38 ** ** **"}
{"replaced":"** S0 ** ** ** ** ** ** 00 00 00 00"}
{"original":"12 ** 12 ** 6a ** ** ** 38 ** ** **"}
{"replace_from_file":"array.tb.bin"}
 
[LIB]
{"name":"libtitanium.so"}
{"original":"00 ** 50 e2"}
{"replaced":"00 00 50 e1"}
 
{"original":"01 0c 80 e2"}
{"replaced":"00 00 a0 e1"}
 
 
[OTHER FILES]
{"name":"/files/shell.dex"}
 
{"original":"0F 00 00 00 1A 00 00 00 0F 00 00 00 59 00 00 00 2F"}
{"replaced":"0F 00 00 00 0F 00 00 00 0F 00 00 00 59 00 00 00 2F"}
 
 
[OTHER FILES]
{"name":"/mnt/sdcard/Android/package-name/files/lives.xml"}
 
{"original":"63 68 65 6C 70 61"}
{"insert":"63 68 65 6c 70 61 61 61"}
 
[END]
Congratulations! Program cracked!
Run Titanium Backup and check License State!
Good Luck!
Chelpus.


Поясню теперь что там где... Я правда думаю, те кому надо, уже поняли....:

Итак:

[BEGIN] - метка начала, весь текст после нее и до первого поля [CLASSES], [LIB], [END] и др. будет выведен в начале лога патча для пользователя.
[PACKAGE] - эта метка говорит о том, что патчить мы будем не dalvik-cache напрямую, а вытащим classes.dex из apk программы, пропатчим (патчами, которые идут следом после идентификаторов [CLASSES] или [ODEX]), создадим образ odex с изменениями и подсунем его приложению. Именно такой образ, к примеру, нужен TitaniumBuckup, т.к. он проверяет его и все чек-суммы внутри него должны быть правильные. Эту метку желательно использовать всегда, т.к. такой патч наиболее правильный, но если это вызывает какие-нибудь проблемы, можно и без нее.
[CLASSES] - тут идут строки для патча classes.dex. Они могу быть поиск(search) и оригинал-замена(original-replaced).
поле original-replaced в original мы указываем последовательность байт, которую ищем в файле, и заменяем ее на байты из replaced. Значения для этих строк обычно смотрят в IDA Pro. Значения байтов в шестнадцатеричной форме, разделенные одинарными пробелами, где ** или ?? - это любой байт (нужны, чтобы патч работал на разных версиях приложений, т.к. некоторые байты меняются).
поле replace_from_file - заменяет байты, начиная с найденного места, на байты из файла с указанным именем и лежащим рядом с файлом самого пользовательского патча (сделано для очень длинных шаблонов замены, которые муторно вбивать в текстовый файл).
поле insert - применяется в случаях, когда необходимо заменить найденный оригинал на количество байт превышающее количество байт оригинального шаблона поиска. Чаще всего это надо в различных текстовых файлах. К примеру, когда в файле xml такое:"lives=9", а надо заменить на "lives=999", именно в этом случае поможет insert, не поменяв при этом данных после "lives=9".
поле search - ищет байты в позициях помеченных R[0, 1, 2, 3, ...], где номер это номер ячейки куда сохраниться байт (номера ячеек должны идти по порядку от 0 и далее и не должны повторяться). К примеру: {"search":"15 01 00 R0 R1 R2 12 ** 0E 00"} означает, что байты на тех позициях будут сохранены в R0, R1, R2. Теперь, когда они найдены и сохранены, можно их использовать в шаблонах поиска замены, только заменяя R на W:
тут:
** или ?? - означает любой байт,
W0, W1, W2 - это сохраненные байты в search,
S0,S1 и SQ- это означает установить переменную smali в 0 (примеры 43->03,54->04...) или 1 (примеры 43->13,04->14...) соответственно, SQ выпавнивает шестнадцатеричные разряды (к примеру 23->33, 62->22...):
к примеру, в коде есть переменная const/4 v?,0x00 - я не просто так там поставил знак ?, а потому что номер ее Вам не известен (к примеру, после обновления приложения он может измениться), но Вы точно знаете, что там заносят в какую-то переменную 0, а Вам надо занести 1, тогда шаблон замены будет выглядеть так:
{"original":"12 ?? ?? ?? ?? ??"}
{"replaced":"12 S1 ?? ?? ?? ??"}
а если Вам надо занести 0, тогда шаблон замены будет выглядеть так:
{"original":"12 ?? ?? ?? ?? ??"}
{"replaced":"12 S0 ?? ?? ?? ??"}
всё остальное просто HEX байты.
Количество байт origanal и replaced обязательно должны совпадать. И обязательно помните, что байты далвик-кэша и classes.dex не все одинаковые, в этом Вы можете убедиться, скопировав файл dalvik-cache из /data/dalvik-cache/ к себе на компьютер и открыв в IDA Pro.
поле group - помечает шаблоны одной группы (группы могут быть от 1 и выше). Что это значит? А значит это то, что если хотя бы один из группы сработает, пользователю покажут диалог, что патч завершился удачно. Это нужно, например, для того, чтобы сделать универсальный патч сразу на много версий одного и того же приложения (к примеру, патч для всех версий Google Play на отключение автообновления).
[ODEX] - вместо идентификатора [CLASSES], можно использовать этот. Тогда изменения classes.dex будут сохранены не в dalvik-cache, где они периодически исчезают при обновлении кэша системой, а в отдельном файле с расширением odex рядом с apk приложения, что зафиксирует все изменения и оставит оригинальный dalvik-cache нетронутым - это на случай, если приложение его проверяет. Можно использовать [ODEX] после [CLASSES], тогда изменения внесутся в далвик-кэш и автоматически зафиксируются в odex.
[ODEX-PATCH] - бывают ситуации, когда нужно изменить уже пропатченное приложение, к примеру, у которого уже сняли проверку лицензии автоматическим патчем, тогда на подмогу приходит эта метка. Все шаблоны <оригинал-замена> после нее будут применены к odex файлу, который уже создали другие патчи. К примеру, это потребовалось впервые в Final Fantasy III, когда люди лечили игру Экстремальным режимом удаления проверки лицензии, но чтобы перевод отображался в правильной кодировке, требовались дополнительные патчи в odex файле, которые стало возможно применить с помощью этой метки.
[LIB] - это означает, что дальше пойдут строки для патча библиотеки этой программы, name - это имя библиотеки (если вместо имени поставить *, то будут патчиться все библиотеки приложения). Иногда в приложении бывают несколько библиотек под разные архитектуры процессоров, тогда лучше использовать [LIB-ARMEABI],[LIB-ARMEABI-V7A],[LIB-MIPS] или [LIB-X86] для нужной библиотеки, чтобы шаблоны от другой библиотеки не применялись к текущей.
[OTHER FILES] - это означает, что дальше пойдут строки для патча файла лежащего в папке приложения /data/data/<имя пакета>, name - это путь от /data/data/<имя пакета> и имя файла. Чтобы файлы там появились, требуется хотя бы один запуск приложения. Еще есть вариант указания пути к файлу на sdcard, для этого надо вписать путь начиная его с "/mnt/sdcard/", тогда, если файл не будет найден по указанному пути, Lucky Patcher будет заменять "/mnt/sdcard/" на различные общепринятые другие варианты расположения sdcard. К примеру так:"/mnt/sdcard/Android/package-name/files/lives.xml"
[FILE_IN_APK] - это означает, что дальше пойдут строки для патча файла, находящегося внутри apk (такой патч будет работать только при применении такого патча для пересборки apk, в режиме обычного патча этот тег игнорируется). Это необходимо для патча файлов, которые не появляются в процессе работы приложения в каком либо из разделов, чтобы получить к ним доступ и пропатчить (к примеру, файлы из assets), либо такой файл после использования удаляется и потом опять распаковывается в место, где был раньше. Пример:
[BEGIN]
Патч для пересборик апк
[FILE_IN_APK]
{"name":"/assets/bin/Data/Managed/O7SharpCompress.dll"}
{"original":"4D 5A 90 00 03 00 00 00 04 00 00 00"}
{"replaced":"00 00 00 00 00 00 00 00 00 00 00 00"}
[END]
Файл пересобран с патчем.
[ADD-BOOT] - Автоматически добавляет текущий пользовательский патч в загрузочный лист, чтобы патч применялся при каждой перезагрузке. Это нужно при патчах библиотек или когда вы используете [CLASSES] без [ODEX] или без [PACKAGE], так как патчится будет далвик кэш, а он имеет свойство обновляться системой и все изменения пропадают.
[COMPONENT] - Иногда приложение отключает своё активити и другие компоненты, чтобы ограничить свою функциональность, тогда может пригодится эта возможность включить ее обратно. Так можно включать активити, сервисы, провайдеры и прочие компоненты. Главное указывать их имена в строгом соответствии с заглавными и строчными буквами. Вот пример, который демонстрирует отключает компонент в приложении с именем com.superApp.adsActivity и разрешение com.android.vending.CHECK_LICENSE
[BEGIN]
Ads disabler
[COMPONENT]
{"disable":"com.superApp.adsActivity"}
{"disable":"com.android.vending.CHECK_LICENSE"}
[END]
Congratulations! Ads hidden!

Или вот пример, который демонстрирует включение компонента в приложении с именем com.superApp.adsActivity и разрешения com.android.vending.CHECK_LICENSE
[BEGIN]
Ads disabler
[COMPONENT]
{"enable":"com.superApp.adsActivity"}
{"enable":"com.android.vending.CHECK_LICENSE"}
[END]
Congratulations! Ads hidden!

[SQLITE] - Иногда в целевом приложении необходимо что-нибудь изменить в базе данных, в которую оно записывает какие-либо события или данные, тогда на помощь приходит этот идентификатор, после него идет конструкция вида:
[BEGIN]
Trial Reset
[SQLITE]
{"database":"/data/data/com.package.megaapp/databases/settings.db"}
{"execute":"DELETE FROM table_settings WHERE name = 'SETTING__LIC'"}
{"execute":"UPDATE table_settings SET UsedDays=0 WHERE name='Trial_set'"}
[END]
Congratulations! You have new Trial Period!

database - это путь к базе данных на вашем устройстве и предположительно на устройствах остальных пользователей. Можно не указывать путь к базе, а указать только имя ее файла, тогда Lucky Patcher попробует ее сам найти.
execute - это SQLite запрос, составляется по обычным правилам (это можно прочесть в интернете).

[SET_PERMISSIONS] - аналог команды linux "chmod разрешения имя_файла" для файлов из папки данных приложения (например дать права только на чтение после редактирования):
[BEGIN]
Trial Reset
[SET_PERMISSIONS]
{"file_name":"/files/stats"}
{"permissions":"777"}
[END]

[COPY_FILE] - копирует файл из папки Lucky Patcher-а в указанную папку с новым именем файла:
[BEGIN]
Копирует файл с деньгами
[COPY_FILE]
{"file_name":"file_for_money.bin"}
{"to":"/data/data/game_package/files/settings.xml"}
[END]

[OTHER FILES]
{"name":"/files/stats"}

{"original":"4D 4D 46 31"}
{"replaced:"4D 00 00 00"}
[END]

[SET_PERMISSIONS]
{"file_name":"/files/stats"}
{"permissions":"444"}
[END]
Congratulations! You have new Trial Period!

[END] - идентификатор конца шаблонов от патчей, весь текст со следующей строки будет выведен при удачном патче программы.

Всё отредактировали, сохраняете и кидаете файл com.keramidas.TitaniumBackup.txt в директорию /sdcard/LuckyPatcher/...
Теперь программа подсвечивается желтым и можно применить к ней этот патч.


Если что, задавайте вопросы. Удачи.