Тривиа Црацк је веома популарна игра и за веб и за мобилне платформе која је донекле направљена по узору на Тривиал Пурсуит. То је најновија лудница у друштвеним играма, која омогућава корисницима да се такмиче са својим пријатељима и странцима у одговарању на питања из низа категорија. Иако никада нисам био превише заинтересован за игре, моја жена је недавно постала велики обожаватељ Тривиа Црацк-а. Након што сам неко време гледао њену игру, одлучио сам да је преузмем и детаљније погледам како је имплементирана.
Почео сам тако што сам надгледао захтеве за веб АПИ направљене преко мреже док сам користио Андроид апликацију. Врло брзо сам приметио нешто занимљиво током рада игре. Чинило се да апликација добија категорију, питање и одговор од Тривиа Црацк сервера пре него што је корисник уопште почео да окреће точкић „категорије“.
Испод је пример одговора који апликација преузима пре него што прикаже овај екран:
{"id": 2747994099,
"opponent": {
"id": 0,
"alerts_count": 0,
"username": "smartplay(tm)"
},
"game_status": "PENDING_APPROVAL",
"language": "EN",
"created": "03/23/2015 08:58:29 EST",
"last_turn": "03/23/2015 08:58:29 EST",
"type": "NORMAL",
"expiration_date": "03/26/2015 08:58:29 EST",
"my_turn": true,
"statistics": {
"player_one_statistics": {
"category_questions": [
{
"category": "GEOGRAPHY",
"correct": 1,
"incorrect": 0,
"worst": false
}
],
"correct_answers": 1,
"incorrect_answers": 0,
"challenges_won": 0,
"questions_answered": 1,
"crowns_won": 0
},
"player_two_statistics": {
"correct_answers": 0,
"incorrect_answers": 0,
"challenges_won": 0,
"questions_answered": 0,
"crowns_won": 0
}
},
"duelGameType": false,
"normalType": true,
"spins_data": {
"spins": [
{
"type": "NORMAL",
"questions": [
{
"question": {
"id": 14996887,
"category": "SPORTS",
"text": "Who was the first woman gymnast to score a perfect ten at the Olympics?",
"answers": [
"Nadia Comaneci",
"Mo Huilan",
"Tatiana Gutsu",
"Agnes Keleti"
],
"author": {
"id": 71534267,
"name": "Florentina Ionela Gagliano",
"username": "florentina.gagliano",
"facebook_id": "100000030456122",
"facebook_name": "Florentina Ionela Gagliano",
"fb_show_picture": true,
"fb_show_name": true
},
"correct_answer": 0,
"media_type": "NORMAL"
},
"powerup_question": {
"id": 8534934,
"category": "SPORTS",
"text": "In basketball, what does it mean to \"kiss it off the glass\"?",
"answers": [
"Make both free throws",
"Pass off someone's back",
"Dribble past two people",
"Hit a shot off the backboard"
],
"author": {
"id": 41439403,
"name": "tsan.819",
"username": "tsan.819",
"fb_show_picture": false,
"fb_show_name": false
},
"correct_answer": 3,
"media_type": "NORMAL"
}
}
]
}
]
},
"available_crowns": [
"SCIENCE",
"ARTS",
"HISTORY",
"ENTERTAINMENT",
"SPORTS",
"GEOGRAPHY"
],
"my_player_number": 1,
"available_extra_shots": 1,
"player_one": {
"charges": 1
},
"player_two": {
"charges": 0
},
"round_number": 1,
"sub_status": "P1_PLAYING_FIRST_TURN",
"previous_sub_status": "P1_WAITING_FIRST_TURN",
"is_random": true,
"unread_messages": 0,
"status_version": 1,
"new_achievements": false,
"my_level_data": {
"level": 1,
"points": 1,
"progress": 33,
"goal_points": 3,
"level_up": false
}
}
Имајте на уму да су категорија, питање, опције одговора и кључеви за тачан одговор укључени у одговор. То значи да би било једноставно идентификовати одговор када се у апликацији затражи да превари игру. Иако није баш етички или поштено за коришћење игара, мислио сам да би то било занимљиво истраживање.
Мој почетни план је био да извршим обрнути инжењеринг Андроид апликације и да кориснику пружим а Тост обавештење о одговору. Почео сам од декомпајлирање апликације и преглед изворног кода. Користио сам греп да претражим извор за неке кључне речи за које сам се надао да ће ми помоћи да пронађем активност питања/одговора. Док сам претраживао неке од потенцијалних резултата, неколико редова ми је привукло пажњу.
v.setText(p);String s1 = "";
if (com.etermax.tools.f.a.a() && h.a("ANSWERS_CHEAT", true))
{
s1 = (new StringBuilder()).append(" (").append(r.getCorrectAnswer()).append(")").toString();
}
B.setText((new StringBuilder()).append(r.getText()).append(s1).toString());
A.setContentDescription(r.getText());
a(B);
u.setVisibility(0);
C.startAnimation(com.etermax.preguntados.ui.a.c.b());
x.setImageResource(com.etermax.preguntados.ui.game.duelmode.h.a(m).a(g, r.getCategory()));
LayoutInflater layoutinflater;
List list;
if (l != null && l == GameType.DUEL_GAME)
{
y.setVisibility(0);
y.setText(c(c.x().h()));
} else
{
y.setVisibility(8);
}
H.setEnabled(false);
layoutinflater = getLayoutInflater(getArguments());
d.a(e.d);
list = r.getAnswers();
Пратећи код, „АНСВЕРС_ЦХЕАТ“ је алудирао на скривени режим варања у игри. Уместо да поново измислим точак, одлучио сам да сазнам како то функционише. Користећи греп, пронашао сам све референце на „АНСВЕРС_ЦХЕАТ“ низ и брзо откривено а упућивање на скривени мени на главној активности контролне табле.
public boolean onOptionsItemSelected(MenuItem menuitem){
if (com.etermax.tools.f.a.a() && menuitem.getItemId() == com.etermax.i.cheat)
{
if (j.a("ANSWERS_CHEAT", true))
{
j.b("ANSWERS_CHEAT", false);
menuitem.setTitle("Enable Answer Cheat");
return true;
} else
{
j.b("ANSWERS_CHEAT", true);
menuitem.setTitle("Disable Answer Cheat");
return true;
}
} else
{
return super.onOptionsItemSelected(menuitem);
}
}
Чинило се да овај код управља подешавањем опције варања, али још увек нисам могао да приступим самом менију. У оквиру исте активности, прегледао сам метод ОнЦреатеОптионсМену у наставку:
public boolean onCreateOptionsMenu(Menu menu){
if (com.etermax.tools.f.a.a())
{
getMenuInflater().inflate(com.etermax.l.preguntados_debug_menu, menu);
return true;
} else
{
return super.onCreateOptionsMenu(menu);
}
}
Већина функционалности режима варања, укључујући скривени мени, изгледала је као да зависи од враћене вредности цом.етермак.тоолс.ф.а.а(). Код за ту класу је испод:
public class a.{
private static boolean a;
private static String b;
public static void a(ApplicationInfo applicationinfo)
{
a = false;
}
public static void a(String s)
{
b = s;
}
public static boolean a()
{
return a;
}
public static String b()
{
return b;
}
public static boolean c()
{
return b != null;
}
}
Чинило се да је ово тачка одлуке коју сам тражио. Промена задатка а = нетачно; до истина требало је да омогући скривени мени. Отворио сам смали репрезентацију класе и пронашао доделу логичког члана.
# direct methods..method public static a(Landroid/content/pm/ApplicationInfo;)V
.locals 1
.prologue
.line 29
const/4 v0, 0x0
sput-boolean v0, Lcom/etermax/tools/f/a;->a: Z
.line 30
return-void
.end method
Променио сам ред 29 (ред исечка бр. 7 изнад) у цонст/4 в0, 1, који поставља вредност на труе. Затим сам поново компајлирао апликацију и инсталирао је. Дугме менија је затим успешно открило скривене опције испод:
„Ансвер Цхеат“ је сада изгледао као подразумевано омогућен, па сам покренуо нову игру за тестирање. Као што се и очекивало, игре су сада додале број након питања, што указује на индекс тачног одговора заснован на нули.
Преузмите закрпљени АПК овде. Имајте на уму да је ово само у истраживачке сврхе; Нисам одговоран за било какво неморално играње!
УРЕДИТИ:АПК Миррор
Ово би требало да послужи као добар пример да се приватност клијентске апликације не може гарантовати и да програмери треба да воде рачуна о томе шта је укључено у њихова компајлирана издања.