Hur jag knäckte Trivia Crack

Trivia Crack är ett mycket populärt spel för både webb- och mobilplattformar som är något modellerat efter Trivial Pursuit. Det är den senaste vurmen inom socialt spel, som låter användare tävla mot sina vänner och främlingar i att svara på frågor från en rad kategorier. Även om jag aldrig har varit särskilt intresserad av spel, har min fru nyligen blivit ett stort fan av Trivia Crack. Efter att ha sett henne spela ett tag bestämde jag mig för att ladda ner den och ta en närmare titt på hur den implementerades.

Jag började med att övervaka webb-API-förfrågningar som gjordes över nätverket när jag använde Android-appen. Mycket snabbt märkte jag något intressant under spelets drift. Det verkade som att appen tog emot kategorin, frågan och svaret från Trivia Crack-servrarna innan användaren ens började snurra på "kategori"-hjulet.

Nedan är ett exempelsvar som appen hämtar innan den här skärmen visas:

{ 

"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

}

}

Observera att kategori, fråga, svarsalternativ och korrekta svarsnycklar ingår i svaret. Detta innebär att det skulle vara enkelt att identifiera svaret när du uppmanas i appen att fuska spelet. Även om det inte är exakt etiskt eller rättvist för spelanvändning, trodde jag att det skulle vara intressant forskning.

Min första plan var att omvända Android-appen och förse användaren med en Rostat bröd meddelande om svaret. Jag började med dekompilera appen och granska källkoden. Jag använde grep för att söka i källan efter några nyckelord som jag hoppades skulle hjälpa mig att spåra frågor/svar-aktiviteten. När jag letade igenom några av de potentiella resultaten fångade några rader min uppmärksamhet.

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

Efter koden anspelade "ANSWERS_CHEAT" på ett dolt fuskläge i spelet. Istället för att uppfinna hjulet på nytt bestämde jag mig för att ta reda på hur det fungerade. Med grep hittade jag alla referenser till "ANSWERS_CHEAT" sträng och snabbt upptäckt referens till en dold meny på huvudinstrumentpanelens aktivitet.

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

}

}

Den här koden verkade klara av att ställa in alternativet för fuskläge, men jag kunde fortfarande inte komma åt själva menyn. Inom samma aktivitet granskade jag metoden OnCreateOptionsMenu nedan:

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

}

}

De flesta av fusklägets funktioner, inklusive den dolda menyn, såg ut att bero på det returnerade värdet på com.etermax.tools.f.a.a(). Koden för den klassen är nedan:

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;

}

}

Detta verkade vara beslutspunkten som jag letade efter. Ändra uppdraget a = falskt; till Sann borde ha aktiverat den dolda menyn. Jag öppnade smali-representationen av klassen och hittade tilldelningen av den booleska medlemmen.

# 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

Jag ändrade rad 29 (snuttrad #7 ovan) till const/4 v0, 1, som ställer in värdet på sant. Jag kompilerade sedan om appen och installerade den. Menyknappen visade sedan framgångsrikt de dolda alternativen nedan:

"Answer Cheat" verkade nu aktiverat som standard, så jag startade ett nytt spel för att testa. Som väntat har spelen nu lagt till ett nummer efter frågorna, vilket indikerar det nollbaserade indexet för det korrekta svaret.

Ladda ner den korrigerade APK-filen här. Observera att detta endast är för forskningsändamål; Jag är inte ansvarig för något omoraliskt spel!

REDIGERA:APK-spegel

Detta bör fungera som ett bra exempel på att integritet för klientapplikationer inte kan garanteras och utvecklare bör vara försiktiga med vad som ingår i deras kompilerade utgåvor.