Ma un ritorno in questa sezione.
Diamo un'occhiata ai codici di rottura.
Quindi questo è molto interessante e forse siamo in grado di capire il nostro primo programma dopo questa sezione,
il nostro primo programma completo dopo la sezione.
Diamo un'occhiata.
Nell'ultima sezione abbiamo dato un'occhiata al seguente programma.
Abbiamo quindi fatto la nostra tipica analisi.
Abbiamo identificato i parametri e i valori di ritorno.
In questo caso, parametri zero, valore di ritorno intero.
Abbiamo anche imparato di più sull'oggetto P zero e sul perché abbiamo un registro locale, anche se non abbiamo
una variabile locale.
Va bene.
Ciò che non abbiamo appreso è che l'istruzione I get è più ampia.
E la domanda, ovviamente, è: che cos'è?
Ricevo un'istruzione e cosa fa questa Ricevo un'istruzione e come faccio a sapere che questa prende
il valore p zero e lo memorizza in V zero?
Beh, anche in questo caso ho ricevuto un po' di aiuto e l'aiuto che ho ricevuto è il set di istruzioni dalvik up code.
Si tratta di una sorta di elenco pieno di istruzioni e della corrispondente descrizione di ciò che fa questa istruzione.
Non sono riuscito a trovare una documentazione ufficiale, il che, nel mio caso, è super ridicolo
che non ci sia.
Ma ho trovato un sito super fantastico che contiene la maggior parte, forse quasi tutte le istruzioni
e le relative descrizioni.
E questo lato voglio mostrarvelo subito.
Quindi passo alla mia macchina virtuale ubuntu, poi vado nel mio browser preferito e cerco i codici
dalvik su Google e questo qui.
Non voglio pronunciare questo nome perché sarebbe sicuramente sbagliato, ma grazie davvero a chi
ha messo online questo sito.
Quindi questo è un Sì.
Un bell'elenco di tutte queste istruzioni è qui e sicuramente vorrete inserire il sito tra i preferiti
perché vi servirà molto.
Li cerco sempre in questo elenco qui e qui.
Diamo un'occhiata all'istruzione I get object.
Scusate, nell'istruzione I get e qui possiamo vedere che abbiamo I get v x, we y field ID e la descrizione c che
legge un campo di istanza in v x instance field è il nostro dot power.
Leggendo un campo di istanza in v x, leggiamo questa potenza in v zero e non deve essere necessariamente
v zero.
Naturalmente, quindi è questo parametro x laggiù e può essere anche v uno per essere tre e così via.
E possiamo anche vedere le istanze a cui fa riferimento V zero.
Questa descrizione è sorprendente perché dice direttamente o immediatamente cosa fa questa istruzione.
E l'autore non si è fermato a questa descrizione.
L'autore inserisce anche un esempio a destra.
Senza questo sito, non avrei imparato in modo intelligente, e quindi sono davvero grato a questo autore.
Ok, rifacciamolo ancora una volta.
Quindi cosa ottengo?
Prendiamo la strada giusta e la leggiamo nella parte sinistra?
Quindi la parte sinistra mantiene questo valore in seguito.
Tutto questo è bello.
Torniamo al nostro esempio.
Questo qui.
Prendiamo questo elenco e vediamo fino a che punto riusciamo a capire questa funzione qui al potere, perché
non abbiamo ancora consultato le istruzioni.
Si esamina il codice dello smiley, si individuano i parametri, i valori di ritorno
e si cerca di completare il puzzle cercando le istruzioni mancanti.
Ok, vediamo come va a finire.
Quindi costruirò ancora una volta questa applicazione, nel caso in cui l'abbia modificata in qualche modo, in modo da utilizzare
questo codice.
Va bene.
Già fatto.
Elimino questa directory qui e facciamo questo secondo strumento APK D.
Ok.
Anche questo è stato terminato.
Poi entriamo nell'applicazione Smiley Comm hacking smiley one e apriamo il nuovo terminale qui.
Possiamo chiudere questo e aprire il lettore di smiley riproducibili, quel file di smiley.
Va bene.
Zoomiamo un po' più in là.
Abilitare Java.
Già.
E concentrarsi anche su questo qui.
Va bene.
Qui.
Ho la mia tavoletta grafica e ora analizziamo il codice degli smiley.
Procederemo lentamente, passo dopo passo, e ricostruiremo l'intero codice Java.
In seguito, vi mostrerò un approccio diverso, il modo in cui mi piace fare il reverse engineering di questo codice.
Ma per ora limitiamoci a ripristinare il codice sorgente Java.
Bene, facciamo un piccolo riepilogo.
Cosa sappiamo già?
Quindi andiamo.
Quindi abbiamo il nostro metodo, questo metodo, public add power.
Questo è il nome del nostro metodo.
Quindi scriviamo questo accanto a questo add power.
Questo metodo ha ora due parametri.
Questi due sono entrambi del tipo Capital II, il che significa che abbiamo due valori interi.
Possiamo trovare queste etichette anche qui.
Se si guarda a questi due, questi sono i nostri parametri.
Già.
Il primo è in un.
E il secondo sta per essere.
Ok.
Poi, abbiamo questo qui, il tipo di ritorno, che restituisce un valore intero.
Pertanto, possiamo scriverlo qui.
E ora abbiamo il nostro prototipo di moda.
Bello, vero?
Poi c'è questo locale.
Locale uno.
Mi dispiace.
In questo modo.
E questo significa che abbiamo un registro locale.
Non sappiamo se questo registro sia solo un segnaposto per il valore di ritorno di un'altra funzione o, ad esempio,
per un campo di istanza.
Oppure se questo registro locale viene utilizzato per memorizzare una variabile.
Se scendiamo un po', possiamo trovare questo qui.
Ciò significa che il nostro registro locale B0 è una variabile locale con il nome sum e che anche questa somma è di tipo
integer.
Quindi scriviamo questo.
Abbiamo un po' di centimetri qui.
Non sappiamo se ora la somma viene inizializzata con un valore o se mantiene il valore.
Al momento conosciamo solo queste informazioni.
Poi abbiamo i parametri delle etichette biennali.
E quello che mi piace fare è tenere traccia di questo aspetto.
Quindi sappiamo che A è P uno e che B è P due.
E lo facciamo anche per la somma delle etichette.
Quindi questa etichetta qui, questa variabile locale sum, è referenziata dal registro V zero in questo
momento.
Questo potrebbe cambiare in seguito, se questo registro viene riutilizzato perché questa etichetta è o questa variabile non
verrà più utilizzata.
Allora la situazione potrebbe cambiare.
Ma per il momento sappiamo che lo zero fa riferimento all'etichetta o alla variabile sum.
Ok, andiamo avanti.
Ok.
Quindi abbiamo capito questa parte e anche questa.
Questa e questa parte.
Ora abbiamo questo qui.
Concentriamoci solo su questo.
Si tratta di una nuova istruzione, un nuovo opcode.
Quindi, diamo un'occhiata a questo o diamo prima un'occhiata a questo.
Abbiamo un const slash quattro, poi abbiamo V zero, virgola zero, zero.
Ora guardiamo qui.
Abbiamo il nostro sito con il codice di suddivisione, quindi stiamo cercando const slash four e qui
abbiamo la descrizione con slash per b x comma lit per questo lit four.
Sembra molto strano, ma se si legge la descrizione, sappiamo cosa significa lit four.
Inserisce la costante a quattro bit in v x.
Quindi abbiamo ottenuto un valore qui.
Ad esempio, il valore due o il valore quattro, e questo valore viene spostato in questo registro settimane.
Abbiamo anche un esempio sul lato destro, quindi diamo un'occhiata a questo.
Abbiamo 2 secondi slash 4v1, poi abbiamo questo hashtag e il valore intero due.
Quindi possiamo rappresentare numeri e smiley con l'hashtag.
Quindi si può scrivere il valore del simbolo della data o si può scrivere zero x la rappresentazione esadecimale di questo valore.
Ok.
E questo cos'è?
E questo è il bytecode.
Questo è il codice esadecimale.
Se si rappresenta questo codice esadecimale in valori binari, questi sono gli uni e gli zeri che eseguono
l'istruzione.
Const per v1, virgola hashtag int a.
In questo modo si sposta il valore da inserire nel registro desiderato.
Va bene.
Non è così difficile per questa istruzione.
Ok, torniamo indietro.
Quindi, ripetiamo ancora una volta questa istruzione.
Abbiamo const slash quattro, we zero, virgola zero, x zero.
Quindi ora stiamo esaminando solo questa istruzione e, come spiegheremo più avanti,
stiamo spostando lo zero in V zero.
E se torniamo al riferimento dalvik, il nostro V0 è il riferimento con v x e questo è riferito
con forma lit.
Perciò sappiamo anche come leggere questo.
Ok, per quanto riguarda la carta, diamo un'occhiata a questo.
Quindi stiamo spostando quattro bit nel registro.
Azzeriamo quattro bit.
Possiamo rappresentarli in questo modo.
Uno, due, tre, quattro.
Questi quattro zeri vengono spostati in noi zero.
Perché spostiamo quattro zeri e non otto, ad esempio, in un byte intero?
Questo dipende dal compilatore.
Quindi il compilatore cerca di risparmiare quanto più spazio o memoria possibile.
In questo caso, il registro viene inizializzato con zero e quattro bit.
La rappresentazione di questo valore è sufficiente, quindi il compilatore ha ottimizzato questo codice e ha utilizzato solo quattro bit per inizializzare questo
valore.
Zero.
Ok, diamo un'occhiata a questa istruzione ancora una volta e più in dettaglio.
Si potrebbe pensare: "Aspetta, c'è dell'altro", ma cerchiamo di capirlo.
Va bene.
Se si guarda indietro nella descrizione, questi due sono indicati con V, X e questo è indicato con
Lit quattro.
Ma che dire di questa illuminazione per questi quattro bit?
Questo è un po' fastidioso o confuso.
Vediamo un esempio reale.
Proviamo a inserire il numero dieci in questo registro.
Azzeriamo il numero dieci, questo qui, 0x8.
Il segno hash è un comune smiley e viene generato automaticamente dallo strumento APK.
Quindi questo è solo per una migliore leggibilità.
Questo non influisce sul codice stesso.
Il valore zero XA viene tradotto in dieci e non disturba il codice stesso.
Lo strumento APK sta aggiungendo un commento.
Quindi possiamo ignorare completamente tutto ciò che viene dopo e il commento, ma ci aiuta a leggere questo codice
un po' più facilmente per avere una visione dei bit che ci servono per la rappresentazione binaria di questo valore.
Dieci Possiamo farlo suddividendo la questione.
Quindi dobbiamo passare dalla casella zero alla casella uno, dalla casella due alla casella tre.
E la quadratura per questo è 1, 2, 4, 8, 16.
Quindi, se si vuole rappresentare il numero dieci, bisogna aggiungere otto più due.
Pertanto, questi due bit sono impostati e il resto no.
Questa è la rappresentazione binaria del numero dieci.
E se si guarda a questo, possiamo vedere che, sì, questo numero si inserisce in quattro bit.
Quindi possiamo anche iniziare dal numero dieci con questa istruzione qui, nel registro, e azzerare.
E ora proviamo a memorizzare il valore 20 con una barra costante per noi zero.
E poi abbiamo 20 che è zero x 14.
Si tratta di 16 quadrati zero, cioè uno per quattro e 16 quadrati uno per uno più più più.
Sono 20.
Sì.
Ok.
Eseguiamo la rappresentazione binaria di questo valore.
20.
Lo stesso approccio viene adottato per lo zero quadrato.
Al punto di partenza.
Al secondo, al terzo e al quarto quadrato.
Abbiamo uno, due, quattro, otto, 16 e qui abbiamo 16 più quattro.
Quattro.
Abbiamo impostato questo bit.
Questo non è questo.
Non è vero.
Va bene.
Qui possiamo vedere che c'è un problema.
Se si cerca di memorizzare quattro bit e svalutare 20, non funziona.
Se ci atteniamo a tutti e quattro i bit, memorizzeremo il valore quattro nel nostro caso in V zero.
Quindi dopo lo zero saremmo a quattro.
Ma potrebbe essere importante che il valore di zero sul registro v zero contenga il valore 20 e quattro
non sia uguale a 20.
Giusto.
Sigma.
Pertanto, il compilatore lancia una freccia e viene segnalato che non è possibile utilizzare o memorizzare questo
valore in un registro a quattro bit.
Dobbiamo estendere questo registro e immagino che il prossimo sia il 16.
Nel nostro caso, quindi, si tratterebbe di un costo pari a 16.
Il 16 ha ora molti bit aggiuntivi qui.
E 1616.
Questo funziona.
Possiamo memorizzare il valore 20 nel nostro registro dei visitatori con questo.
Quindi, se scrivete del codice, non ci interessa perché è qualcosa che il compilatore fa automaticamente.
Ma se si vuole applicare una patch a questa applicazione e si vuole aumentare questo valore qui, bisogna
fare attenzione a questo aspetto e poi si può capire qual è la prossima istruzione possibile per questo.
Ad esempio, slash 16.
Oppure possiamo semplicemente usare const, perché const, per impostazione predefinita, è impostato su 32 bit.
Quindi, se si incontra un'icona slash 4 o slash 16, si deve pensare a questo valore.
E ancora, se avete bisogno di aumentare questo, inoltre, sostituite anche questa istruzione non solo il valore.
Quindi, sostituendo questi valori qui, ad esempio con zero x 14, non funzionerà perché const
per quattro bit non può contenere questo valore.
Pertanto, basta rimuovere questo qui e siamo a posto.
Quindi credo che questa istruzione sia ora chiara, non è vero?
Ecco fatto.
Puliamo un po' questo punto.
Ok.
Abbiamo quindi parlato di questa istruzione.
A cosa serve?
Beh, scherzavo.
Diamo un'occhiata.
Abbiamo la nostra parte.
Alcuni in alcuni si riferiscono a V zero.
In questo caso, stiamo spostando il valore zero in V zero, il che significa che stiamo spostando il valore zero nella
nostra variabile somma qui.
E mi piace tenere traccia di questi registri.
Quindi scriverei anche l'uguale a zero.
Ok.
Quindi inizializziamo la nostra somma con il valore zero.
Questo è ciò che fa questa istruzione qui.
Giusto.
Quindi comprendiamo anche questo.
Di questo abbiamo già parlato.
Eccoci qua.
Abbiamo una nuova istruzione.
Questo qui.
Se consultiamo il codice Dalvik, diamo un'occhiata a questo.
Quindi scriviamo questo.
Abbiamo inserito un annuncio.
Con zero virgola p uno.
Virgola p due.
Ok.
Quindi abbiamo tre registri in questa istruzione e in questa.
Sì, sono abbastanza a mio agio nel dire cosa fa questo, ma cerchiamo di capirlo.
Ok.
Torniamo all'opcode, vediamo.
Stiamo cercando un int e possiamo vederlo int we x we y we set calculate v y plus we set e mette il risultato
in settimane.
Va bene calcola noi y più noi set.
Quindi questi due elementi vengono sommati.
E il risultato è pensato in settimane.
Ok.
Credo che anche questo non sia così difficile.
Diamo un'occhiata all'esempio qui sopra.
È tre, tre, due, tre, due e mette il risultato a zero.
È esattamente la stessa cosa.
Ok, diamo un'occhiata al nostro codice.
Quindi dividiamo ancora una volta il tutto.
E poi diciamo: ok.
P uno viene sommato a P due.
E il risultato di tutto ciò viene pensato in We zero.
Sostituiamo i registri con le etichette originali.
Scriviamo quindi questa operazione matematica.
Quindi abbiamo V zero come uguale, p uno più p due.
Questo è ciò che fa questa istruzione.
Ok.
Ora sostituiamo i registri con le nostre etichette.
Sappiamo che il nostro V0 è la somma e quindi la somma è uguale a P uno è il nostro a più, p due è il nostro b OC.
Questo è ciò che fa questa istruzione.
Ripuliamo il tutto e scriviamolo.
Sì, più pulito.
Beh, questo qui.
La somma è uguale ad A più B.
Ok.
Quindi abbiamo anche questo.
Infine, c'è il nostro ritorno.
Noi zero.
Sappiamo anche cosa fa questo.
Il nostro ritorno è zero, che è stato referenziato o assegnato con una qualche etichetta E.
Alcuni.
E sì, ci siamo.
Abbiamo riavviato il codice sorgente Java dal codice smiley.
Non è ridicolo?
Bello, a mio parere.
Lo è sicuramente.
Quindi è molto bello scriverlo.
In questo modo possiamo ricostruire l'intero codice Java e questo vi aiuterà a imparare sempre di più gli smiley.
Nel mio caso, non sono un vero fan della scrittura nel codice originale di Java, perché possiamo
semplicemente prendere questa funzione e decompilarla o ricompilarla in Java, per poi vedere che questo
è il codice Java corrispondente alla funzione smiley.
Nel mio caso, vorrei scriverlo in modo un po' diverso, perché non siamo interessati a quelle
funzioni Java, o almeno a quei nomi Java, ma siamo più interessati a quale registro ha più valore, perché vogliamo modificare
alcuni valori per migliorare il nostro livello di potenza, migliorare i nostri oggetti d'oro e cose
del genere.
E questo deve essere fatto a livello di registro.
Quindi non possiamo semplicemente dire ad alcuni.
Ora è pari a 40.
Quindi non funziona in questo modo.
Pertanto, dobbiamo andare nel codice smiley a sinistra e poi dobbiamo applicare una patch al registro, che
è esattamente il passo da eseguire all'interno dell'inizializzazione o di qualcos'altro.
Ora vi mostrerò il mio approccio.
È più o meno lo stesso, ma io lo etichetto in modo un po' diverso.
Quindi, lasciatemi pulire questo e poi diamo un'occhiata a questo.
Ok.
Non fraintendetemi, il codice sorgente di questo viaggio è fantastico.
E se vi piace attenervi a questo, ovviamente, fate così.
Ora vi mostrerò il mio approccio.
E questo è solo il mio riferimento personale.
Se vi piace farlo allo stesso modo, allora sentitevi liberi di approfondire anche l'etichettatura.
Ma se volete attenervi all'approccio Java, non c'è alcun problema.
È sufficiente conoscere o essere in grado di ricostruire il codice della funzione smiley.
Vediamo quindi come lo scriverei normalmente.
Inizio con lo stesso approccio.
Metodo di potenza del bordo pubblico.
Ecco quindi il nostro metodo per aggiungere energia.
Poi abbiamo questi due parametri e non li chiamerei A e B, ma P uno e P
due.
Mi piace attenermi ai registri, quindi nel mio caso nominerei le tette.
Quindi nel mio caso avrei chiamato questo int p uno e int p due e poi sì, anche il valore di ritorno è intero.
Siamo pronti a partire.
Solo una piccola differenza rispetto all'approccio precedente.
Ok.
Allora dovrei passare alla riga successiva.
In questo caso, però, non mi interessa questo locale, perché lo sto facendo per un'istruzione dopo l'altra e non ho intenzione
di entrare in questo e guardare questo verso il basso, perché non mi interessa questa etichetta.
Vediamo, se non vi interessa, come si presenta l'approccio.
Ora possiamo procedere dall'alto verso il basso, istruzione dopo istruzione.
Poi abbiamo questi parametri e qui abbiamo già questi due.
E naturalmente possiamo anche usare le etichette qui, per dire che questo è a e questo è B, non
è un problema.
Ma di solito non mi interessano queste etichette.
Ok.
Poi, abbiamo questo qui e possiamo scriverlo esattamente così com'è.
Questo valore viene appreso in V zero.
E normalmente non mi piacciono questi valori esadecimali.
Quindi scriverei con zero come uguale a zero.
Ok, ora abbiamo questa etichetta qui e possiamo vedere come il registro OC B0 sia stato disabilitato
e sia di tipo intero.
Quindi lo scriverei come commento qui, ma vorrei tenere traccia di v zero e non etichettare
alcuni.
Quindi scriverei int alcuni.
In questo modo.
E possiamo passare alla prossima.
Possiamo vedere che OC P1 viene sommato a P2 e il risultato del ripristino viene memorizzato in V zero.
E lo scriviamo esattamente così com'è.
Lo zero è uguale a P1 più P2.
E infine, ma non per questo meno importante, restituiamo questo registro v zero.
Questo è il modo in cui mi piace farlo, perché esaminando il codice non dobbiamo sostituirlo,
registrare le etichette o cose del genere.
Possiamo vedere direttamente, ad esempio, la nostra P 1 qui, la P 2 qui.
Questi due vengono aggiunti.
Ciò significa che abbiamo un nuovo valore in questo registro, che verrà poi restituito.
E qui inizializziamo questo registro.
Quindi, facendo in questo modo, per me è più pulito.
Ma questa è la mia preferenza personale.
Se si desidera sostituire questi valori e attenersi al codice Java, è possibile farlo.
OC A prescindere dall'approccio utilizzato, questo dovrebbe essere sempre lo stesso.
Quindi date un'occhiata al codice smiley e analizzate riga per riga le istruzioni che non conoscete.
Per favore, cercateli.
Questo tipo di tabella di codice è super fantastico e lo faccio quasi sempre.
Mi imbatto anche in molte nuove istruzioni e le cerco nella descrizione.
Forse scrivo qualche programmino per capire alcune istruzioni complesse, ma dopo, sì,
so cosa fanno.
E poi lo scrivo nel modo seguente, come potete vedere in questo disegno a matita, questo
qui.
In questo modo, anche il codice di uno smiley complesso viene diviso in singoli pezzi e noi possiamo
capirlo e scriverlo in seguito.
È piuttosto sorprendente se date un'occhiata a sinistra e vi rendete conto che avete già compreso ogni singola
istruzione di questo codice smiley e che, prima di iniziare questo corso, forse non conoscevate nemmeno
lo smiley.
Quindi questo è già un grande passo avanti.
E ci spingeremo sempre più in là in questo capitolo.
Va bene.
Ok.
Nella prossima sezione estenderemo un po' questo programma.
Aggiungeremo nuove variabili, forse nuove funzioni, cose del genere.
E così facendo, ripeteremo i passaggi più volte.
Potrebbe risultare un po' noioso, ma ripetendo questa operazione si acquisirà sempre più familiarità
con Smiley.
A un certo punto, quando si fa clic, si fissa un codice smiley e ci si rende conto che sono in grado
di leggere questo codice smiley in un modo incredibile.
Credetemi, avrete questo momento.
Va bene.
Quindi, non vedo l'ora di vedervi nella prossima sezione.