Trivia Crack הוא משחק פופולרי מאוד עבור פלטפורמות אינטרנט ומובייל, המעוצב במידת מה על פי Trivial Pursuit. זהו הטירוף האחרון בתחום המשחקים החברתיים, המאפשר למשתמשים להתחרות מול חבריהם וזרים שלהם בתשובות לשאלות ממגוון קטגוריות. למרות שמעולם לא התעניינתי במשחקים, אשתי הפכה לאחרונה למעריצה ענקית של טריוויה קראק. לאחר שצפיתי בה משחקת זמן מה, החלטתי להוריד אותו ולבחון מקרוב כיצד הוא יושם.
התחלתי במעקב אחר בקשות ה-API המבוצעות ברשת תוך שימוש באפליקציית אנדרואיד. מהר מאוד הבחנתי במשהו מעניין במהלך פעולת המשחק. נראה היה שהאפליקציה קיבלה את הקטגוריה, השאלה והתשובה משרתי Trivia Crack עוד לפני שהמשתמש החל לסובב את גלגל ה"קטגוריה".
להלן דוגמה לתגובה שהאפליקציה מאחזרת לפני הצגת מסך זה:
{"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
}
}
שימו לב שהקטגוריה, השאלה, אפשרויות התשובה ומקשי התשובה הנכונות כלולים כולם בתגובה. זה אומר שזה יהיה פשוט לזהות את התשובה כשתבקשו מהאפליקציה לרמות את המשחק. למרות שזה לא בדיוק אתי או הוגן לשימוש במשחקים, חשבתי שזה יהיה מחקר מעניין.
התוכנית הראשונית שלי הייתה לבצע הנדסה לאחור של אפליקציית אנדרואיד ולספק למשתמש א הרמת כוסית הודעה על התשובה. התחלתי ב פירוק האפליקציה וסקור את קוד המקור. השתמשתי ב-grep כדי לחפש במקור כמה מילות מפתח שקיוויתי שיעזרו לי לעקוב אחר פעילות השאלות/תשובות. תוך כדי חיפוש בכמה מהתוצאות הפוטנציאליות, כמה שורות משכו את תשומת לבי.
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();
בעקבות הקוד, "ANSWERS_CHEAT" רמז למצב צ'יט נסתר במשחק. במקום להמציא את הגלגל מחדש, החלטתי לגלות איך זה עובד. באמצעות grep, מצאתי את כל ההפניות ל-"ANSWERS_CHEAT" חוּט ובמהירות גילה א התייחסות לתפריט נסתר בפעילות לוח המחוונים הראשי.
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);
}
}
נראה שהקוד הזה טיפל בהגדרת אפשרות מצב הצ'יט, אבל עדיין לא הצלחתי לגשת לתפריט עצמו. במסגרת אותה פעילות, סקרתי את שיטת OnCreateOptionsMenu להלן:
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);
}
}
רוב הפונקציונליות של מצב הצ'יט, כולל התפריט הנסתר, נראתה כאילו היא תלויה בערך המוחזר של com.etermax.tools.f.a.a(). הקוד עבור אותה מחלקה הוא להלן:
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;
}
}
זה נראה היה נקודת ההחלטה שחיפשתי. שינוי המשימה a = שקר; ל נָכוֹן היה צריך להפעיל את התפריט הנסתר. פתחתי את ייצוג ה-smali של הכיתה ומצאתי את המטלה של החבר הבוליאני.
# 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 למעלה) ל const/4 v0, 1, שמגדיר את הערך ל-true. לאחר מכן ערכתי מחדש את האפליקציה והתקנתי אותה. לחצן התפריט חשף בהצלחה את האפשרויות הנסתרות למטה:
"Answer Cheat" נראה כעת מופעל כברירת מחדל, אז פתחתי משחק חדש לבדיקה. כצפוי, המשחקים צורפו כעת מספר אחרי השאלות, המציין את האינדקס מבוסס האפס של התשובה הנכונה.
הורד את ה-APK המתוקן כאן. שימו לב שזה למטרות מחקר בלבד; אני לא אחראי לשום משחק לא מוסרי!
לַעֲרוֹך:מראה APK
זה אמור לשמש דוגמה טובה לכך שלא ניתן להבטיח פרטיות של יישומי לקוח ומפתחים צריכים להיות זהירים לגבי מה שנכלל במהדורות הקומפילציה שלהם.