Trivia Crack er et meget populært spil til både web- og mobilplatforme, som er lidt modelleret efter Trivial Pursuit. Det er den seneste dille inden for socialt spil, der giver brugerne mulighed for at konkurrere mod deres venner og fremmede i at besvare spørgsmål fra en række kategorier. Selvom jeg aldrig har været særlig interesseret i spil, er min kone for nylig blevet en stor fan af Trivia Crack. Efter at have set hende spille et stykke tid besluttede jeg at downloade det og se nærmere på, hvordan det blev implementeret.
Jeg begyndte med at overvåge de web-API-anmodninger, der blev foretaget over netværket, mens jeg brugte Android-appen. Meget hurtigt bemærkede jeg noget interessant under spillets drift. Det så ud til, at appen modtog kategorien, spørgsmålet og svaret fra Trivia Crack-serverne, før brugeren overhovedet begyndte at dreje på "kategori"-hjulet.
Nedenfor er et eksempel på svar, som appen henter, før denne skærm vises:
{"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
}
}
Bemærk, at kategori, spørgsmål, svarmuligheder og korrekte svartaster alle er inkluderet i svaret. Dette betyder, at det ville være ligetil at identificere svaret, når du bliver bedt om at snyde spillet i appen. Selvom det ikke ligefrem er etisk eller fair for spilbrug, tænkte jeg, at det ville være interessant forskning.
Min oprindelige plan var at reverse engineering af Android-appen og give brugeren en Ristet brød besked om svaret. Jeg startede ved dekompilere appen og gennemgang af kildekoden. Jeg brugte grep til at søge i kilden efter nogle nøgleord, som jeg håbede ville hjælpe mig med at spore spørgsmål/svar-aktiviteten. Mens jeg søgte gennem nogle af de potentielle resultater, fangede et par linjer min opmærksomhed.
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 hentydede "ANSWERS_CHEAT" til en skjult snydetilstand i spillet. I stedet for at genopfinde hjulet, besluttede jeg mig for at finde ud af, hvordan det fungerede. Ved at bruge grep fandt jeg alle referencer til "ANSWERS_CHEAT" snor og hurtigt opdaget -en henvisning til en skjult menu på den primære dashboard-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);
}
}
Denne kode så ud til at håndtere indstillingen af snydetilstand, men jeg var stadig ikke i stand til at få adgang til selve menuen. Inden for den samme aktivitet gennemgik jeg OnCreateOptionsMenu-metoden nedenfor:
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);
}
}
Det meste af snydetilstandsfunktionaliteten, inklusive den skjulte menu, så ud til, at den afhang af den returnerede værdi af com.etermax.tools.f.a.a(). Koden for den klasse er nedenfor:
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;
}
}
Det så ud til at være det beslutningspunkt, jeg ledte efter. Ændring af opgaven a = falsk; til rigtigt burde have aktiveret den skjulte menu. Jeg åbnede smali-repræsentationen af klassen og fandt tildelingen af det booleske medlem.
# 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
Jeg ændrede linje 29 (snippet linje #7 ovenfor) til const/4 v0, 1, som sætter værdien til sand. Jeg kompilerede derefter appen igen og installerede den. Menuknappen afslørede derefter de skjulte muligheder nedenfor:
"Answer Cheat" så nu ud til at være aktiveret som standard, så jeg startede et nyt spil for at teste. Som forventet tilføjede spillene nu et nummer efter spørgsmålene, der angiver det nul-baserede indeks for det rigtige svar.
Download den lappede APK her. Bemærk, at dette kun er til forskningsformål; Jeg er ikke ansvarlig for noget umoralsk gameplay!
REDIGERE:APK spejl
Dette bør tjene som et godt eksempel på, at privatlivets fred for klientapplikationer ikke kan garanteres, og udviklere bør være forsigtige med, hvad der er inkluderet i deres kompilerede udgivelser.