Gli algoritmi genetici e il machine learning sono due aspetti del concetto più generale di intelligenza artificiale che hanno possibili implicazioni anche nella digital forensics.
Infatti, mentre con il machine learning riusciamo a classificare o approssimare dei risultati estrapolati dalla nostra indagine forense, con gli algoritmi genetici possiamo giungere a produrre l’oggetto target dell’indagine stessa.
Indice degli argomenti
Algoritmi genetici e machine learning: applicazioni nella digital forensics
L’intelligenza artificiale sostanzialmente può essere molto d’aiuto nella classificazione e previsione di eventi, nel cercare l’origine di qualcosa o riconoscere dei pattern o delle difformità.
Pensiamo, ad esempio, a:
- cambiamenti nei comportamenti dell’utente o del computer mediante l’analisi di alcuni registri o schemi;
- sapere quale cella della rete mobile può agganciare un utente in una determinata posizione;
- ricerca di malware che analizza i comportamenti o le firme;
- rilevare alcune anomalie nel traffico di rete;
- classificare alcuni file multimediali per la loro tipologia;
- rendere le relazioni tra artefatti nei Big Data;
- creare automaticamente uno storyboard a partire da eventi (ad es. ultimo file aperto, sequenza temporale, connessione di dispositivi USB, shellbag, modifica di data e ora ecc.);
- prevedere qualcosa usando l’analisi dei social media;
- cracking.
È bello pensare che, in un futuro prossimo, parecchio lavoro di analisi potrà essere eseguito dalle IA, considerando che i dati sono sempre più numerosi, di grandi dimensioni e sempre più correlati tra loro anche tra diversi sistemi e mezzi tecnologici.
Inoltre, l’IA potrà anche analizzare il comportamento digitale e scovare anomalie o notare cose che potrebbero sfuggire ad un’analisi umana o eseguita con software non muniti d’intelligenza.
L’utilità degli algoritmi genetici
Gli algoritmi genetici sono degli algoritmi che imitano l’evoluzione della specie per giungere ad un obbiettivo. Quindi, partendo da genitori casuali, essi genereranno figli che, tramite cross-over e mutazioni, giungeranno a produrre l’oggetto target.
Ad esempio, se l’oggetto target è la frase “ciao a tutti”, l’algoritmo genetico è così composto:
Insieme_di_geni=” abcdefghijklmnopqrstxywz”
Ossia i geni sono le 26 lettere dell’alfabeto e il carattere spazio all’inizio della sequenza.
L’algoritmo genera due genitori o cromosomi casuali di lunghezza pari alla frase target “ciao a tutti”, che è lunga 12 caratteri:
Genitore1=”azfduuqmiobs”
Genitore2=”mhkklrstyu jj”
Effettua quindi il crossover dei geni, ossia scambia alcuni caratteri del Genitore1 con quelli del Genitore2:
Genitore1=”azfduuqmiobs”
Genitore2=”mhkklrstyu jj”
creando un figlio:
Figlio=”azfkklqmiobs”
Poi il figlio ha una mutazione genetica, ad esempio cambia un solo gene, con uno preso dall’Insieme_dei_geni:
Figlio=”avfkklqmiobs”
A questo punto, vi è la funzione di “fitness” ossia la selezione naturale che va a contare quanti “geni” del Figlio sono presenti nella frase “ciao a tutti”, nella stessa posizione.
In questo caso la funzione restituirà un valore di 0, perché nel confronto non ci sono geni uguali nella stessa posizione:
“ciao a tutti”
“avfkklqmiobs”
Quindi, il Figlio si accoppierà con un altro individuo generato dalla mutazione del figlio precedente, così da ottenere altre sequenze di caratteri (stringhe), fino a che non giungerà a qualcosa di simile:
“ciab z putti”
Che ha una fitness di valore 9 perché ben 9 caratteri coincidono e sono nella stessa posizione con quelli della frase target.
Seguendo le ulteriori mutazioni e crossover, il figlio finale otterrà una fitness di 12, che significherà che ha raggiunto lo stadio evolutivo desiderato.
Ecco un esempio di funzione di fitness per decodificare una stringa base64, partendo da stringhe casuali di caratteri:
geneSet = ‘ abcdefghijklmnopqrstuvwxyz’
cyph = ‘Y2lhbyBhIHR1dHRpIGUgZGl2ZXJ0aXRldmkgc2VtcHJl’ # base64 encoded without trail “==” of “ciao a tutti e divertitevi sempre”
def get_fitness(child):
b64 = base64.b64encode(child.encode(“utf-8”))
cguess = str(b64, “utf-8”)
return sum(1 for expected, actual in zip(cyph, cguess) if expected == actual)
La funzione, come si può vedere, si incrementa di 1 per ogni carattere contenuto nel cromosoma (child) che corrisponde alla lettera e nella stessa posizione.
Classificare i risultati con il machine learning
Come dicevamo, il machine learning rappresenta un sottoinsieme dell’Intelligenza Artificiale ed è al contempo un sovrainsieme delle reti neurali e deep learning.
Tramite machine learning si possono classificare o approssimare dei risultati tramite regressione lineare e altre diavolerie matematiche.
- Creare un dataset, anche un file CSV va bene.
- Addestrare l’algoritmo utilizzando una parte del dataset come training ed una parte come test.
- Interrogarlo su un dato anche non presente nel dataset.
- Ricevere il risultato con un percentuale d’accuratezza stimata.
Vediamo come funziona in sintesi facendo un esempio (completamente inventato) di machine learning supervisionato, ossia diamo all’algoritmo un dataset (insieme) di dati numerici come, ad esempio:
num.ore_online | Utilizzo_cpu | Totale_dati_scambiati | Tipologia |
7 | 73 | 32 | normal |
9 | 66 | 94 | normal |
9 | 56 | 25 | normal |
8 | 29 | 58 | normal |
5 | 90 | 66 | suspect |
6 | 79 | 71 | suspect |
1 | 36 | 32 | suspect |
2 | 68 | 98 | suspect |
Quando inseriremo la richiesta sapremo se, utilizzando il computer per 3 ore, è stato osservato un utilizzo della CPU del 67% e una mole di dati scambiati pari a 85 GB, quindi se il “comportamento” del computer è normale o sospetto: l’algoritmo avrà imparato dagli esempi e trarrà la sua conclusione.
Accuracy Train: 81.82 % Accuracy Test: 77.27 %
Predicted target name: [‘suspect’]
[‘time_online’, ‘cpu’, ‘data_exchanged’, ‘type’]
[3, 67, 85] [‘suspect’]
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
# Load dataset
url = “data.csv”
names = [“time_online”,”cpu”,”data_exchanged”,”type”]
dataset = pd.read_csv(url, names=names,header=0)
# Split-out validation dataset
dataset= pd.DataFrame(dataset)
array = dataset.values
#print (array[:,0:2])
#print(dataset.head(1000))
X = array[:,0:3]
y = array[:,3]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.6, random_state=0)
model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)
pred_train = model.predict(X_train)
pred_test = model.predict(X_test)
acctest=accuracy_score(y_test,pred_test)
acctrain=accuracy_score(y_train,pred_train)
valori=[3,67,85]
prediction = model.predict([valori])
print(“Accuracy Train:”,round(acctrain*100,2),”% Accuracy Test: “,round(acctest*100,2),”%”)
print(“Predicted target name: {}”.format(prediction),” n”,names,” n”,valori,” “,prediction)
Il codice è abbastanza leggibile e lineare, fatto dai seguenti passi:
- Caricamento del dataset data.csv.
- Impostazione della variabile X come le colonne 0,1,2 della matrice, che corrispondono a time_online, cpu e data_exchanged, ossia i “data”.
- Variabile y che rappresenta la “label” o “feature”, l’etichetta del valore d’uscita, la variabile target.
- Poi c’è la fase di training e test.
- Si sceglie il classificatore KNN (KNeighborsClassifier).
- Si fa la “predizione” dando in pasto i valori [3,67,85].
- Stampa del risultato a video.
In sostanza, si deduce da una serie di osservazioni come sarà l’oggetto richiesto, attraverso le stime calcolate dal dataset iniziale. Ne discende che più grande è il dataset più l’algoritmo sarà accurato.
In sostanza, il machine learning può essere utilizzato per classificare qualcosa di ignoto, partendo dai dati che l’algoritmo ha letto e imparato oppure per generare una previsione numerica utilizzando un “regressore”.
Classificazione e regressione: le definizioni
Se l’attività di previsione è classificare le osservazioni in una serie di etichette finite, in altre parole per “nominare” gli oggetti osservati, si dice che l’attività è una classificazione.
D’altra parte, se l’obiettivo è prevedere una variabile target continua, solitamente numerica, si dice che sia un’attività di regressione.
Il termine predizione racchiude dunque i concetti di:
- classificazione: quando la classe, la nostra variabile y, è un’etichetta, quindi c’è un numero finito di classi, ogni etichetta ha una serie di “data” (osservazioni);
- regressione: quando la classe è un valore numerico e non è un insieme finito, quindi a tante osservazioni corrispondono dei valori numerici e si può prevedere il valore numerico che uscirà, dopo l’elaborazione, che non è già fissato come classe nel dataset. Ad esempio, il valore di una casa, l’andamento di un titolo in borsa eccetera.
Pertanto, normalmente quando si parla di previsione si pensa alla regressione e non alla classificazione.
Conclusioni
L’intelligenza artificiale, come già detto, può essere anche utilizzata per predire alcuni valori, grazie agli operatori di cosiddetta “logistic regression”, il che potrebbe essere molto utile al contrasto dei fenomeni di cyber crime e di tanto altro ancora.
L’argomento è vasto, complicato ma affascinante, per questo ci vengono in aiuto tantissimi strumenti open source, distribuiti apposta in questa modalità proprio perché la comunità scientifica vuole il massimo della collaborazione e condivisione della conoscenza per fare passi avanti nello sviluppo dell’AI.
Abbiamo strumenti e librerie come:
Ma anche innumerevoli programmi su piattaforme come GitHub, oltre a framework gratuiti di sviluppo come Anaconda 3, Spyder, PyCharm, solo per parlare del linguaggio Python, ma c’è tanto anche i C++ e Java.
Non mancano, inoltre, numerosi tutorial in varie lingue sia sul web testuale sia su YouTube. Ed infine molti dataset già pronti all’uso.
Quindi non ci sono scuse, se la cosa vi interessa, tutto ciò che vi serve è a portata di clic, almeno per iniziare.
PS: io l’ho fatto.