Changes between Initial Version and Version 1 of Ruzzle-cheater


Ignore:
Timestamp:
03/16/13 22:43:50 (12 years ago)
Author:
mancausoft
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Ruzzle-cheater

    v1 v1  
     1Parlando su irc con sand mi ha fatto venire la voglia di indagare di piu' su ruzzle per capire come funziona, un bel divertimento per il tempo libero. La prima cosa che ho scoperto e' stato che se ti colleghi via ssh al cellulare e porti indietro l'orologio puoi aumentarti il tempo all'infinito, ma questo trucchetto non era abbastanza bello da sfamare la mia curiosita', sono trucchetti semplici.
     2
     3Quindi scarico l'apk sul pc e tramite un software di cui non ricordo il nome ho trasformato l'apk in un jar. Fatto questo ho estratto tutto il contenuto del jar (ho controllato e si chiama dex2jar) . Estratto i jar vedo che quello che usano e' una libreria C loro piu' tutto codice java. Non avevo mai usato un decompiler java e non pensavo uscisse qualcosa di leggibile da umano, ma ho provato lo stesso e il risultato e' stato molto ma molto stupefacente. Codice umanamente leggibile, a parte qualche piccola eccezione ma per il resto facilmente leggibile.
     4
     5guardiamo un po' la struttura del codice:
     6
     7{{{
     8src $ ls
     9android  com  org  se
     10}}}
     11
     12
     13dentro se/maginteractive/rumble/ troviamo il codice di ruzzle:
     14
     15
     16{{{
     17ls
     18activities  ad  adapters  api  BuildConfig.java  datastructure  GCM  GLES2 
     19Manifest.java  model  R.java  Rumble.java  util  view
     20
     21}}}
     22
     23la prima cosa che faccio e' cercare dove inviano i dati, e l'ho trovato facilmente dentro il file api/RumbleConnector.java. Guardando la funzione che invia ogni cosa noto una cosa che nemmeno un principiante con un minimo di cervello farebbe:
     24
     25 
     26{{{
     27private static String post(String s, String s1)
     28        throws RumbleException
     29    {
     30        HttpPost httppost;
     31        HttpResponse httpresponse;
     32        int i;
     33        int j;
     34        Log.d("RumbleConnector", (new StringBuilder()).append("URL: ").append(s).toString());
     35        Log.d("RumbleConnector", (new StringBuilder()).append("Data").append(s1).toString());
     36        BasicHttpParams basichttpparams = new BasicHttpParams();
     37        SchemeRegistry schemeregistry = new SchemeRegistry();
     38        schemeregistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
     39        SSLSocketFactory sslsocketfactory = SSLSocketFactory.getSocketFactory();
     40        Scheme scheme = new Scheme("https", sslsocketfactory, 443);
     41        schemeregistry.register(scheme);
     42        DefaultHttpClient defaulthttpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(basichttpparams, schemeregistry), basichttpparams);
     43        httppost = new HttpPost(s);
     44        httppost.addHeader("Content-Type", "application/json");
     45        httppost.addHeader("User-Agent", (new StringBuilder()).append("Android/Rumble/").append(RumbleDataSource.getInstance().getCurrentVersion()).toString());
     46        HttpResponse httpresponse1;
     47
     48}}}
     49
     50In pratica mettono nei log non solo la url ma anche i dati che inviano. Non potevo credere ai miei occhi
     51alzi la mano chi non pensa che sia una cosa stupida! (fucilate a vista chi alza la mano per favore :D). Utilizzano questa post quasi per tutto, poi esiste una post2 che non e' altro che un copia e incolla della post cancellando le righe di log, la utilizzano per inviare il punteggio.
     52
     53A questo punto mi collego via ssh al cellulare, faccio su per ottenere i permessi di root e lancio logcat ridirezionando l'output su file, apro ruzzle e inizio a fare le operazioni tipiche.
     54
     55Velocizzando il racconto, inizio a capire il tutto come funziona e scrivo un programma in python, facendo l'errore di usare twisted (non e' che non mi piace twisted, anzi, ma per quello che dovevo fare non serviva avere qualcosa di asincrono). Roba noisa e ripetiva, bisogna inviare roba codificata in json verso un server http e leggere il risultato in json. Roba molto noiosa di cui non mi va di parlare.
     56
     57Comunque inviato il login mi accorgo di una cosa che farebbe inorridire anche chi ancora non lo ha fatto, In pratica dopo il login ti viene inviato un numero di sessione che puoi usare all'infinito ed e' sempre uguale, anche se cambi la password!!! (Perche' fare cose del genere? chiedetelo a quelli di ruzzle che io non ho nessuna voglia di chiedere). In pratica se qualcuno si logga su ruzzle utilizzanod il mio cellulare, mi ritrovo tra i log il numero di sessione che potro usare all'infinito per giocare con l'account dell'amico, molto comodo. Piu' vado avanti e piu' mi sembrano dei principianti.
     58
     59Sorvoliamo questo fatto ed andiamo avanti, invio una richiesta di elenco di partite e noto un altra cosa da principianti, in pratica mi arriva il punteggio che ha fatto l'avversario anche dei round che ancora non ho inviato. PERCHE???!!!! ALLORA VOLETE AIUTARE CHI BARA???
     60
     61La cosa preoccupante e' che non mi arriva in nessun modo la scacchiera, ma tra i dati che mi arrino per ogni round noto 3 valori che mi incuriosiscono:
     62
     63
     64
     65{{{
     66 'rounds': [{'gameId': '9108341182362867352', 'player2Moves': '204540459E3049A3049530563112212341267341267A3126A512659E4126504126BE4126953126331273512736A51273651154156733156A5156A9E5156A724156BE315634156326156327A21593159A3159E2150415840', 'player2Done': 'true', 'seed1': '800038988', 'seed2': '830013712', 'seed3': '129958401', 'player1Moves': '21233621536210110372652623362732A623A6233A6733156A49A67349A6723BA624BA6253A6153A6105459A725459A733459A36A9546A9503159A5159A633736A5736A952BEA3ED95326953156335673356723367A33695415840495840', 'player2Score': '357', 'persistedRound': 'false', 'round': '0', 'player1Score': '335', 'player1Done': 'true'}, {'gameId': '9108341182362867352', 'player2Moves': '10120154015AB4015AE401523401526601526AB10450459EB50459634045AB4045AE5045AEB5045A6350452763048C5048CDE7048CDEA5304856048527B604852762049305AE405AEB405A631122123212631265212541254041258C11531540315AB315AE415AEB415A633152641527B4152733104521453148C4148DE', 'player2Done': 'true', 'seed1': '1370501326', 'seed2': '995886043', 'seed3': '906124985', 'player1Moves': '4326AB376AB476ABE376AE2ABE49548C4958404DC8414DC8454DC840396233967B3962159625405962541396AB396AE3DEA63DEAB2B733B7233B7213B72533721252635263552637B5526BAE345A6345AB445273595237649527649527B4952734AB7234AB7254FB7234FB7252376532104543258C09', 'player2Score': '665', 'persistedRound': 'false', 'round': '1', 'player1Score': '696', 'player1Done': 'true'}, {'gameId': '9108341182362867352', 'player2Score': '0', 'player2Done': 'false', 'seed1': '362894109', 'seed2': '7957389', 'seed3': '578740907', 'player1Moves': '20123562125632B7326732DA6', 'persistedRound': 'false', 'round': '2', 'player1Score': '30000', 'player1Done': 'true'}], 'chatLastUpdated': '-1', 'state': '1', 'pairCounter': '5', 'player2MostWordsInRound': '0', 'type': '0', 'cacheKey': 'readGame_9108341182362867352', 'dictionaryVersion': '1', 'player2Score': '1022', 'lastUpdated': '1363390659377', 'player1BestWord': 'LELLA', 'player2User': {'username': 'mancausoft', 'ranking': '0', 'premium': 'false', 'useFacebookImage': 'false', 'userId': '879878479', 'matchesPlayed': '0', 'avatarId': '2025'},
     67}}}
     68
     69cio' che mi incuriosisce e':
     70
     71{{{
     72 'seed1': '1370501326', 'seed2': '995886043', 'seed3': '906124985',
     73}}}
     74
     75Torno al codice, e vado nel file model/Board.java e noto che come immaginavo la soluzione sta in questi valori. seed1 viene inviata ad unaa funzion srand dentro la libreria c loro, e poi richiamando la random dentro la stessa funzione escono dei numeri random che servono a generare la scacchiera. seed2 invece e' il seme che serve per calcolare i bonus. Di seed3 invece non vedo traccia nel codice, sembra essere alquanto inutile, della serie noi lo inviamo se poi ci viene un idea lo usiamo :D.
     76
     77Il problema e' che non riesco ad usare questa libreria sul pc, ma solo su android, allora inizio a guardare i numeri generati con i vari seed e li confronto con la rand di python e niente. Poi ci penso su e provo a generare numeri in C e con mia immenso stupore vedo che i numeri generati usando lo stesso seme sono gli stessi!! Quindi passo a riscrivere la funzione in python che estrae la scacchiera:
     78
     79
     80{{{
     81import ctypes
     82LIBC = ctypes.cdll.LoadLibrary("libc.so.6")
     83letterChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
     84letterCount = [114, 18, 50, 20, 105, 14, 24, 8, 124, 0,
     85                0, 36, 36, 60, 82, 23, 1, 85, 63, 71,
     86                18, 19, 0, 1, 0, 17]
     87letterPoints = [
     88                1, 5, 2, 5, 1, 5, 8, 8, 1, 10,
     89                10, 3, 3, 3, 1, 5, 10, 2, 2, 2,
     90                3, 5, 10, 10, 10, 8
     91                ]
     92numChar = 26
     93
     94bonusDist = [[1, 1, 0, 0, 14],
     95             [2, 1, 1, 0, 12],
     96             [1, 2, 2, 1, 10]]
     97
     98bonusTiles =['D', 'T', 'V', 'W', ' ']
     99
     100tiles = ""
     101points = []
     102bonus = ""
     103
     104def generateLettersUsingSeed(seed1, seed2, round):
     105        global tiles
     106        global points
     107        global bonus
     108        a = []
     109        p = []
     110        tiles = ""
     111        points = []
     112        bonus = ""
     113
     114        for i in xrange(numChar):
     115                for j in xrange(letterCount[i]):
     116                        a.append(letterChar[i])
     117                        p.append(letterPoints[i])
     118        seed1 = int(seed1)
     119        seed2 = int(seed2)
     120        round = int(round)
     121        LIBC.srand(seed1)
     122        for i in xrange(16):
     123                k = LIBC.rand()
     124                k %= len(a)
     125                tiles += a.pop(k)
     126                points.append(p.pop(k))
     127        a = []
     128        for i in xrange(5):
     129                for j in xrange(bonusDist[round][i]):
     130                        a.append(bonusTiles[i])
     131        LIBC.srand(seed2)
     132        for i in xrange(16):
     133                k = LIBC.rand()
     134                k %= len(a)
     135                bonus += a.pop(k)
     136
     137}}}
     138
     139In pratica e' un modo per estrarre delle lettere a caso dando un peso ad ogni lettera. Non mi va di commentarlo, ho solo ricopiato quello che fa ruzzle in java.
     140
     141
     142
     143
     144
     145
     146