Привет Гость!
Ты можешь:
Войти или зарегистрироваться

Забыл пароль
Регистрация
Меню сайта
Главная страница
Моды ПК игр Форум Flash игры/журналы Помощь сайту WAP/PDA версия сайта Мы вКонтакте
Категории
Уроки по модификации java [176]
Уроки по переводу java игр [15]
Программы для компьютера [102]
Программы для телефона [85]
Модификация смартфонных игр [15]
Symbian, Android, iPhone и т.д.
Прочее [35]
Уроки по модификации ПК игр [10]
Мини-чат
Главная » Статьи » Уроки по модификации java

04.12.2012, 18:17

Взлом Tanks Mobile

Рассмотрим возможность взлома J2ME-игр на примере танчиков.

Инструменты:
WinRAR (или другой архиватор который умеет работать с zip архивами), думаю что есть у всех.
Декомпилятор, я использую Java Decompiler.
Блокнот или любой другой текстовый редактор.
Сама игра…

Разархивируем игру и смотрим содержимое:
*.map – карты игры
*.png – картинки
*.mid – музыка
*.class – скомпилированный исходный код игры ( то что нам нужно).
Декомпилируем файлы *.class в Java Decompiler с включенной функцией «Deobfuscate»
Получаем файлы *.java ( исходный код игры), которые можно открыть любым текстовым редактором.
Рассмотрим содержимое этих файлов. В файле k.java находим такой кусок кода:
Code
if(m_aI == 1){
  q.m_bSprite.setFrame(2);
  q.m_bSprite.setPosition(getWidth() - 22, getHeight() - 20);
  q.m_bSprite.paint(g);
  q._aStringI("Благодарим вас за регистрацию! Приятной игры!"
  , g, getWidth() - 15, getWidth() / 2, (getHeight() / 2 + q.m_agI) - 5, 1, true, true);
  return;
  }
  if(m_aI == 2){
  q.m_bSprite.setFrame(3);
  q.m_bSprite.setPosition(3, getHeight() - 20);
  q.m_bSprite.paint(g);
  q._aStringI("Неверный ключ. Обратитесь за помощью на сайт www.tanchiki.ru"
  , g, getWidth() - 15, getWidth() / 2, (getHeight() / 2 + q.m_agI) - 5, 1, true, true);
  return;
  }


То, что разработчики держали строки типа «Благодарим вас за регистрацию! Приятной игры!» в самом коде, очень облегчило нам задачу поиска, но так будет далеко не во всех играх. Чтобы регистрация прошла необходимо, чтобы переменная m_aI = 1.

Ищем все, что связано с изменением этой переменной в файле k.java.
И находим такой кусок кода:
Code
_L6:
  int i = Integer.parseInt(m_aString);
  boolean flag = false;  
  if(q.m_afI == 3)
  {
  long l;
  String s;
  long l1;
  l1 = (l1 = Integer.parseInt((s = String.valueOf(l = q.m_aeI)).substring(0, 1))  
  + Integer.parseInt(s.substring(1, 2)) + Integer.parseInt(s.substring(2, 3))  
  + Integer.parseInt(s.substring(3, 4)) + Integer.parseInt(s.substring(4, 5))  
  + Integer.parseInt(s.substring(5, 6)) + Integer.parseInt(s.substring(6, 7))) * 321L + 213L & 255L;
  if((s = String.valueOf(l = (l = (l = (l = (l = (l ^= 0x1c91bfL) ^ l1) ^ l1 << 8) ^ l1 << 16) << 3)  
  * 3L + 2129L).substring(0, 7)).substring(0, 4).compareTo(m_aString.substring(1, 5)) == 0)
  flag = true;
  }
  if(flag)
  {
  m_aI = 1;
  q._aStringIV("temp", 2, i);
  q.m_eZ = true;
  } else
  {
  m_aI = 2;
  }
  this;
  goto _L8


Переменная m_aI=1, если flag==true. А переменная flag принимает значение true, если выполняется довольно громоздкая и непонятная проверка ( разработчики постарались ).

В строчках:

int i = Integer.parseInt(m_aString);

и

l1 = (l1 = Integer.parseInt((s = String.valueOf(l = q.m_aeI)).substring(0, 1))
+ Integer.parseInt(s.substring(1, 2)) + Integer.parseInt(s.substring(2, 3))
+ Integer.parseInt(s.substring(3, 4)) + Integer.parseInt(s.substring(4, 5))
+ Integer.parseInt(s.substring(5, 6)) + Integer.parseInt(s.substring(6, 7))) * 321L + 213L & 255L;

видим 2 неизвестные переменные:

m_aString
q.m_aeI

Сначала разберемся с q.m_aeI, так как l1 участвует в проверке кода.
Открываем q. java и ищем переменную m_ aeI. Мы находим ее только в строчке:

public static int m_aeI = 0;

Но этого недостаточно, так как получается, что в k.java вызывается переменная из q.java, которая равна нулю… Следовательно, ищем изменение этой переменной в остальных классах.
В i.java находим такие строчки:
Code
int k;
  if((k = q._aStringII("temp", 1, 0)) == 0){
  k = q._aIII(0xf462b, 0x98967f);
  k = 0x1c9c380 + k;
  q._aStringIV("temp", 1, k);
  }
  q.m_aeI = k % 0x989680;
  q.m_afI = (k - k % 0x989680) / 0x989680;
  obj = String.valueOf(k);
  obj = ((String) (obj)).substring(0, 4) + " " + ((String) (obj)).substring(4, 8);


Смотрим, какое значение получает переменная k при q._aIII(0xf462b, 0x98967f). Открываем q.java и ищем функцию _aIII

public static int _aIII(int i, int x){
int i1;
return (i1 = Math.abs(m_aRandom.nextInt())) % (x - i) + i;
}

Исходя из этого переменной k задается случайное значение…
Проанализировав получаемые значения k, а так же исходя из этих строчек:

obj = String.valueOf(k);
obj = ((String) (obj)).substring(0, 4) + " " + ((String) (obj)).substring(4, 8);

и

q.m_bString = "T" + obj + " " + s;

Получаем, что k это первые 8 цифр из 12-значного кода, которые генерируется в игре при первом запуске.

Теперь объединяем все воедино и пишем подбор ключа

Используемые переменные:

Kod – первые 8 цифр из кода, который генерируется при запуске игры
Kod1 – дополнительная переменная
Klych – ключ который необходим для регистрации
Code
//вначале считываем код в переменную kod
  //далее идет объединенные части из разных классов, которые мы раскопали
  Kod1 = Kod % 0x989680;
  obj = String.valueOf(Kod);
  long l;
  String s;
  long l1;
  boolean progress=true;
  String Klych ="10000000";
  while(progress){
  Klych = String.valueOf(Integer.parseInt(Klych)+1);
  l1 = (l1 = Integer.parseInt((s = String.valueOf(l = Kod1)).substring(0, 1))  
  + Integer.parseInt(s.substring(1, 2)) + Integer.parseInt(s.substring(2, 3))  
  + Integer.parseInt(s.substring(3, 4)) + Integer.parseInt(s.substring(4, 5))  
  + Integer.parseInt(s.substring(5, 6)) + Integer.parseInt(s.substring(6, 7))) * 321L + 213L & 255L;
  if((s = String.valueOf(l = (l = (l = (l = (l = (l ^= 0x1c91bfL) ^ l1) ^ l1 << 8) ^ l1 << 16) << 3)  
  * 3L + 2129L).substring(0,7)).substring(0,4).compareTo(obj.substring(1, 5)) == 0){
  progress=false;
  //вывод переменной Klych
  }
  }


Для ускорения перебора можно вынести:

l1 = (l1 = Integer.parseInt((s = String.valueOf(l = Kod1)).substring(0, 1)) + ... + 213L & 255L;

и

String.valueOf(l = (l = (l = (l = (l = (l ^= 0x1c91bfL) ^ l1) ^ l1 << 8) ^ l1 << 16) << 3) * 3L + 2129L).substring(0, 7);

за цикл,так же можно установить "шаг перебора" равным 1000.

Получаем следующий код:
Code
Kod1=Kod % 0x989680;  
  long l;
  String s;
  String Klych ="10000000";  
  long l1;
  boolean progress=true;
  l1 = (l1 = Integer.parseInt((s = String.valueOf(l = Kod1)).substring(0, 1))  
  + Integer.parseInt(s.substring(1, 2)) + Integer.parseInt(s.substring(2, 3))  
  + Integer.parseInt(s.substring(3, 4)) + Integer.parseInt(s.substring(4, 5))  
  + Integer.parseInt(s.substring(5, 6)) + Integer.parseInt(s.substring(6, 7))) * 321L + 213L & 255L;
  s = String.valueOf(l = (l = (l = (l = (l = (l ^= 0x1c91bfL) ^ l1) ^ l1 << 8) ^ l1 << 16) << 3) * 3L + 2129L).substring(0, 7);
  while(progress){
  Klych = String.valueOf(Integer.parseInt(buf)+1000);
  if ( s.substring(0, 4).compareTo(Klych.substring(1, 5)) == 0){
  //вывод Klych
  progress=false;  
  }
  }


Теперь этот код можно перенести на любой другой язык программирования или оставить в J2ME.
Вместе со статьей идут два Key-Gen'а в котором он реализован… (J2ME и VВ.NЕТ)
Вот так, просто анализируя код мы создали свой генератор ключей…

Взлом Tanks MobileАвтор: BlackFan
Оформление: aNNiMON
Редактор: SlaDER
Категория: Уроки по модификации java | Добавил: Tommy_M
Просмотров: 3183 | Комментарии: 9 | Рейтинг: 5.0/1

Всего комментариев: 9
Спам
Trice   (24.01.2013 21:32) [Материал]
Блин как вы все это понимаете. Даже геометрия проще, наверно

Спам
Dagger   (15.12.2012 16:43) [Материал]
ValekS, ну по идее ты прав,заменить выражение на ему противоположное,но это надо только через байт код делать,при декомпиляции там дохрена косяков появляется

Спам
RblSb   (07.12.2012 18:13) [Материал]
GPRScode, здесь описано как работает генератор. ValekS, про компиляцию хз, ибо я не думаю что деобфускация пройдет без ошибок, а так правильно, если игра не вылетит из-за выполнения регистрации при включении :)

Спам
ValekS   (07.12.2012 15:04) [Материал]
А не проще сменить это - if(m_aI == 1) на это - if(m_aI != 1), затем скомпилировать класс и вкинуть его в игру? Или он не скомпилируется?

Спам
Tommy_M   (07.12.2012 14:16) [Материал]
GPRScode, проще, но урок полезен для обучения взломам.

Спам
Mad1999   (07.12.2012 09:32) [Материал]
facepalm Ничё не понял

Спам
Mr_Leks   (06.12.2012 12:32) [Материал]
Щито?:D

Спам
GPRScode   (05.12.2012 22:16) [Материал]
А не проще ли использовать уже готовый кейген? Благо такой есть.

Спам
Dagger   (05.12.2012 14:09) [Материал]
Видел не раз эту статью,но примеров к статье-ни разу.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

о, привет
Новинки
  • Файлы
  • Статьи
  • Новости

Rise Of Antares
Комментов: 1 | Загрузок: 40
РЕЗНЯ 3D: Not city of sins
Комментов: 0 | Загрузок: 97
Vice Multi-Player 0.1 beta RC 8-4-9-5
Комментов: 0 | Загрузок: 16
GTA San Andreas Beta 1
Комментов: 1 | Загрузок: 170
Galaxy Force 2 FINAL
Комментов: 42 | Загрузок: 1
Haunting abandoned mansion (color mod)
Комментов: 0 | Загрузок: 148
Deadly game Resident Evil 7 DLC
Комментов: 0 | Загрузок: 224
GTA SA FLY
Комментов: 0 | Загрузок: 278
GTA SA Mobile: Definitive Edition
Комментов: 1 | Загрузок: 490
QUAKE
Комментов: 51 | Загрузок: 431

ODN Remake - скриншоты
Комментов: 0 | Просмотров: 23
O. D. N Remake
Комментов: 0 | Просмотров: 115
Новый сайт с мобильными загрузками - Oldfag
Комментов: 7 | Просмотров: 1478
Здорово и вечно 2 свободное человечество анонс номер два
Комментов: 9 | Просмотров: 1406
Дневник разработки "Шизофрения 3D" #2 - Концепция
Комментов: 2 | Просмотров: 1419
Дневник разработки "Шизофрения 3D" #1 - Общая инфа
Комментов: 0 | Просмотров: 1370
Maximum Carnage: No Way Home
Комментов: 0 | Просмотров: 1283
Случайный мод
2251 455 5 4.4
Статистика
Онлайн всего: 5
Гостей: 5
Пользователей: 0
Пользователи
Гости сайта

[ Нас сегодня посетили ]
При копировании материалов, желательно оставлять ссылку на этот сайт!
© Tommy_M 2009-2024 | Хостинг от uCoz