Cum am spart Trivia Crack

Trivia Crack este un joc foarte popular atât pentru platformele web, cât și pentru cele mobile, care este oarecum modelat după Trivial Pursuit. Este cea mai recentă nebunie în jocurile sociale, permițând utilizatorilor să concureze cu prietenii și străinii lor pentru a răspunde la întrebări dintr-o serie de categorii. Deși nu am fost niciodată foarte interesat de jocuri, soția mea a devenit recent o mare fană a Trivia Crack. După ce am urmărit-o o perioadă de joc, am decis să-l descarc și să mă uit mai atent la modul în care a fost implementat.

Am început prin a monitoriza solicitările web API făcute prin rețea în timp ce folosim aplicația Android. Foarte repede, am observat ceva interesant în timpul funcționării jocului. Se părea că aplicația primea categoria, întrebarea și răspunsul de la serverele Trivia Crack înainte ca utilizatorul să înceapă chiar să rotească roata „categorii”.

Mai jos este un exemplu de răspuns pe care aplicația îl preia înainte de a afișa acest ecran:

{ 

"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

}

}

Rețineți că categoria, întrebarea, opțiunile de răspuns și cheile de răspuns corect sunt toate incluse în răspuns. Aceasta înseamnă că ar fi simplu să identificați răspunsul atunci când vi se cere în aplicație să trișeze jocul. Deși nu este tocmai etic sau echitabil pentru utilizarea în jocuri, m-am gândit că ar fi o cercetare interesantă.

Planul meu inițial a fost să fac inginerie inversă a aplicației Android și să ofer utilizatorului un Paine prajita notificarea răspunsului. Am început prin decompilarea aplicației și revizuirea codului sursă. Am folosit grep pentru a căuta în sursă câteva cuvinte cheie care speram că mă vor ajuta să urmăresc activitatea de întrebări/răspunsuri. În timp ce căutam unele dintre rezultatele potențiale, câteva rânduri mi-au atras atenția.

 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();

În urma codului, „ANSWERS_CHEAT” a ​​făcut aluzie la un mod de trișare ascuns în joc. În loc să reinventez roata, am decis să aflu cum funcționează. Folosind grep, am găsit toate referințele la „ANSWERS_CHEAT” şir si repede descoperit referire la un meniu ascuns din activitatea tabloului de bord principal.

 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);

}

}

Acest cod părea să se ocupe de setarea opțiunii modului cheat, dar tot nu am putut accesa meniul în sine. În cadrul aceleiași activități, am revizuit metoda OnCreateOptionsMenu de mai jos:

 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);

}

}

Majoritatea funcționalității modului cheat, inclusiv meniul ascuns, părea că depinde de valoarea returnată a com.etermax.tools.f.a.a(). Codul pentru acea clasă este mai jos:

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;

}

}

Acesta părea a fi punctul de decizie pe care îl căutam. Schimbarea sarcinii a = fals; la Adevărat ar fi trebuit să activeze meniul ascuns. Am deschis reprezentarea smali a clasei și am găsit atribuirea membrului boolean.

# 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

Am schimbat linia 29 (linia fragmentului #7 de mai sus) în const/4 v0, 1, care setează valoarea la adevărat. Apoi am recompilat aplicația și am instalat-o. Butonul de meniu a expus apoi cu succes opțiunile ascunse de mai jos:

„Answer Cheat” părea acum activat în mod implicit, așa că am pornit un nou joc pentru a testa. După cum era de așteptat, jocurile au adăugat acum un număr după întrebări, indicând indexul bazat pe zero al răspunsului corect.

Descărcați APK-ul corectat Aici. Rețineți că acest lucru este doar în scopuri de cercetare; Nu sunt responsabil pentru niciun joc imoral!

EDITAȚI | ×:Oglindă APK

Acesta ar trebui să servească drept un bun exemplu că confidențialitatea aplicației client nu poate fi garantată și dezvoltatorii ar trebui să fie atenți la ceea ce este inclus în versiunile lor compilate.