Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

Видеокурс программиста и крэкера 5D 2O17
(актуальность: август 2O17)
Свежие инструменты, новые видеоуроки!

  • 400+ видеоуроков
  • 800 инструментов
  • 100+ свежих книг и статей

УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Ломаем j2me:majiplayer

Обсудить статью на форуме

Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.

Автор: F@nT0M <lokomot476@mail.ru>

Это моя первая статья на данном ресурсе, поэтому заранее извиняюсь, если нарушу своим изложением какие-то местные традиции.
Дано:majiplayer.jar
DJ Java Decompiler
Java Bite и jbloader
HEX-редактор

Ломать я буду(точнее уже сломал, а вам покажу) плеер majiplayer, для мобильников. скачать можно тут http://series40.kiev.ua/java_progs/5295-maji-player-240320.html.
Для начала запустим приложение на теле или эмуляторе(я запускал на nokia 6300) и зайдем в меню->Register. Здесь нам предлагают ввести рег код, но у нас его нет...
Поэтому открываем total commander(или что вы там юзаете, главное чтоб в архивах умел искать), жмем Alt+F7 в качестве места поиска вводим путь до jar-файла и отмечаем "с текстом" "Register". тотал выдает bx.class(имя малоинформативное из-за обфуксации). Вынимаем его из архива и открываем в DJ. После непродолжительной работы получаем исходный код нашего класса(транслированные в байткод файлы .class относительно легко декомпилируются, в отличие от PE, поэтому анализ java программ в этом отношении проще). жмем Ctrl+F и снова набираем "Register". Первое вхождение передает строку "Register" в конструктор суперкласса, а нам это неинтересно, поэтому жмем F3 и попадаем в метод public final void c() (опять эта обфуксация, она нам дальше очень сильно попортит кровь).

public final void c()
{
if (!em.a().a())
{
em.a().a(new er(this));
return;
}
if (!a())
{
o o1 = new o(new bk(2));
Object obj = "Register at\nhttp://majimob.com";
((am) (obj = new am(((String) (obj)), 2, 80))).h(false);
((am) (obj)).d(false);
((am) (obj)).a().b(0, 0, 2, 2);
((am) (obj)).a().a(null);
((am) (obj)).a().e(0);
o1.a(((ah) (obj)));
((bg) (obj = new bg("Code"))).a().b(1, 1, 2, 2);
o1.a(((ah) (obj)));
((bg) (obj = new bg(c()))).a().b(1, 1, 2, 2);
((bg) (obj)).h(true);
o1.a(((ah) (obj)));
((bg) (obj = new bg("Registration"))).a().b(1, 1, 2, 2);
o1.a(((ah) (obj)));
((fo) (obj = new fo())).a().b(0, 0, 2, 2);
o1.a(((ah) (obj)));
((fo) (obj)).a(new es(this, ((fo) (obj)), o1));
obj = new dc("Ad Mode", MajiPlayerMidlet.getIcon("adBrowser.png"));
dc adc[] = {
obj, new dc("Later", MajiPlayerMidlet.getIcon("cancel.png"))
};
if (fm.a("Unregistered Version", o1, adc) == obj)
ba.o(true);
e();
}
}
Что же мы видим? Сначала проверяется результат, возвращаемый функцией какого-то левого класса, поэтому игнорим и смотрим следущеее условие. Ага, тут уже вызывается "местная" функция, поэтому неплохо бы ее изучить. Внизу у DJ есть список всех методов класса с прототипами. Но из-за обфуксации методов с именем "а" там аж 33 штуки!!!. Поэтому попытаемся восстановить ее сигнатуру. Поскольку ее результат стоит в if-е, она должна возвращать boolean. Ей ничего не передается, поэтому наш искомый прототип: boolean a(). Жмем Ctrl+Home, чтобы начать с начала, Ctrl+F, и вводим нашу сигнатуру.
Мгновене, и метод public final boolean a() найден!.

public final boolean a()
{
RecordStore recordstore = null;
RecordEnumeration recordenumeration = null;
if (e)
try
{
e = false;
recordenumeration = (recordstore = RecordStore.openRecordStore("registration", false)).enumerateRecords(null, null, false);
String s = new String(recordenumeration.nextRecord());
recordenumeration.destroy();
recordenumeration = null;
recordstore.closeRecordStore();
d_java_lang_String_fld = a(c(), s);
}
catch (RecordStoreNotFoundException _ex)
{
d_java_lang_String_fld = null;
a(recordstore);
a(recordenumeration);
return false;
}
catch (RecordStoreException recordstoreexception)
{
a(recordstore);
a(recordenumeration);
recordstoreexception.printStackTrace();
}
return d_java_lang_String_fld != null && !d_java_lang_String_fld.startsWith("V");
}

Так, смотрим что делается. Ага, читается rms (Record Management Store-Хранилище записей, этакая штука, позволяющая на j2me приложениям сохранять информацию на диск и удобно управлять ею. На самом деле это БД), и мы опять видим наше "registration". А это значит мы где-то рядом. Далее смотрим что и где возвращается: Один return в catch блоке, и один в конце функции. Попытаемся исправить их и посмотрим что выйдет. Править будем в байткоде, поэтому потребуется Java Bite. открываем его, жмем в меню Classes->Add Java Class и выбираем наш bx.class
Тыкаем слева на + и далее разворачиваем ветку методов. Жмем на метод "a" и... Но что это? даже по длине видно, что это не наш метод!. Дело в том, что эта программа не видит перегруженных методов, а только один самый первый с данным именем. Вот тут-то нам и потребуется jbloader. Проделываем в нем те же шаги и в конце выделяем наш класс слева и Functions->Unique names for oveloaded functions. Оп, и у нас в ветке методов все функции. Теперь сохраняем этот класс(все в том же меню classes) под именем bx_original_deobfucsated.class. Теперь делаем его копию и называем bx_edited_deobfucsated.class. открываем этот последний и будем патчить. Для этого надо найти нужную функцию, но как это сделать? А очень просто)) Загружаем наш файл снова в DJ, декомпилим и ищем "public final boolean a"(мы ведь теперь знаем полный прототип и можем существенно сузить круг поиска). Видим, что наш метод носит название a_$$3. Ну и патчим его в JavaBite. А что именно патчить?-спросите вы. А патчить мы будем возвращаемые значения. Как мы видим, в оригинале, если хранилище записей не найдено, то бросается исключение RecordStoreNotFoundException _ex и в обработчике возвращается false. Также в конце функции возвращается результат выполнения логического И. Вот их и пропатчим. Оператор возврата в байткоде выглядит как ireturn(i-integer, значит что со стека снимается значение целочисленного типа, к коим относится и boolean, и возвращается в качестве результата работы функции). Значит надо посмотреть значение, которое последним кладется на стек и заменить его нужным нам. Смотрим, и видим, что это iconst_0.Логично предположить, что это false. Но нам то надо true! А где его взять? Смотрим в самый конец функции, и видим вот такой код
0076 990005 ifeq 0000007B
0079 04 iconst_1
007A AC ireturn
007B 04 iconst_0
007C AC ireturn
Видим, что во одном случае возвращается iconst_1, а в другом-уже знакомое нам iconst_0, которое есть false. но тогда получается, что iconst_1=true. Вот его мы и пихаем перед всеми ireturn. Как пихать? double-click на строке перед ireturn и из выпадающего списка выбираете нужную инструкцию(в нашем случае-iconst_1). Теперь сэйвим и получаем патченый класс. Но не спешите кидать его в jar!. Ведь он у нас деобфусцирован->имена всех методов поменялись и ниче работать не будет!. Можно было вы воспользоваться Functions->Restore overloaded function names, но ма моей Win7x32 Ultimate после выбора этого пункта прога умирает(ошибка в jbhook.dll, еще один повод звняться реверсингом :-) ). Поэтому будем делать по старинке, то есть ч/з HEX-редактор. Что нам собственно нужно? А нужно нам немного: посмотреть какие байты изменились(их должно быть 2, мы ведь меняли в 2-х местах) и пропатчить их в оригинальном, недеобфусцированном файле(можете для надежность стянуть заново из джарника, если не уверены, что ничего не меняли в уже имеющемся). Я искал разницу с помощью тотала:выделяем оба файла bx_original_deobfucsated.class и bx_edited_deobfucsated.class и жмем Файлы->Сравнить по содержимому. Видим, что изменилось 2 байта по смещениям 2ED2 и 2EF6 с 03 на 04. Понятное дело, в оригинальном bx.class эти же байты будут по другим смещениям, и чтобы их найти открываем нех-редактор, загружаем в него наш bx.class и ищем в нем байты, окружающие наши изменения(я для надежности брал всю строку: 00DB03AC4E2BB800 для первого байта и 6899000504AC03AC для второго. К сожалению тотал не позволяет копировать числа(только как текст), поэтому придется ручками). Видим, что первая строка нашлась по 2D28, а вторая-по 2D48. патчим байты, сохраняем, закидываем в jar и заливаем на тело/в эмуль. Вот и все, из меню изчез пункт Register, а это значит, что прога считает себя зареганой и нам осталось сделать самое главное:-)-написать cracked by %cracker_name%. Но это я думаю вы и сами сможете.



Обсуждение статьи: Ломаем j2me:majiplayer >>>


Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS