Grep e Strings due giganti a confronto

Il tempo libero serve anche a sperimentare e quando si ha la passione per la computer forensics, son dolori....

Tramite Nigilant32 (presente nella parte Live di Helix 2) faccio l'immaginedella Ram del mio PC, mentre è in uso, e la salvo sul file RAM.IMG.

ram.img - dump della mia ram 1.3Gb

Tramite editor esadecimale, vedo che tra le tante stringhe, contenute nel file, ne prendo una a casaccio per fare il mio test, la stringa è "awatarami".
Cerco con strings e il parametro -t d (che mi genera anche l'offset in decimale) ottenendo:

strings -t d ram.img | less
33593  Skype z awatarami

Quindi segno l'offset come: 33593

Poi cerco con grep ed i parametri
-i ignora il maiuscolo/minuscolo;
-a tratta il file binario come se fosse testuale;
-b stampa il byte offset;
-o Mostra solo la parte di linea che coincide con la stringa cercata;

grep -iabo awatarami ram.img
4923:awatarami

Segno l'offset: 4923
Ho cercato la parola "awatarami" ed ho ottenuto due offset diversi....ma qual'è quello giusto?
Passo all'uso di xxd (editor esadecimale da riga di comando) e con -s lo faccio partire dall'offset trovato:

 xxd -s 4923 ram.img | less
00133b: 0366 2e0f 011e 1203 662e a10c 0090 9090  .f......f.......
00134b: 9090 9090 9090 9090 900f 22d8 662e a1ec  ..........".f...
00135b: 0266 0bc0 7403 0f22 e066 2ef7 0604 0002  .f..t..".f......
00136b: 0000 0074 1666 b980 0000 c00f 3266 0d00  ...t.f......2f..
00137b: 0800 0066 b980 0000 c00f 3066 2e8b 2e10  ...f......0f....
00138b: 0066 2e8b 0eac 0066 2e8b 1ee8 0266 2ea1  .f.....f.....f..
00139b: e002 662e 8b3e 0800 0f22 c066 ea20 456e  ..f..>...".f. En
0013ab: 8008 0000 0000 0000 0000 0000 0000 0000  ................
0013bb: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0013cb: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0013db: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0013eb: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0013fb: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00140b: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00141b: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00142b: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00143b: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00144b: 0000 0000 0000 0000 0000 0000 0000 0000  ................

Non c'è traccia della parola "awatarami"....
Provo con l'offset ottenuto da strings:

xxd -s 33593 ram.img | less
08339: 2053 6b79 7065 207a 2061 7761 7461 7261   Skype z awatara
08349: 6d69 204b 6c6f 6e69 6573 2e3c 6272 2f3e  mi Klonies.
08359: 3c61 2068 7265 663d 2273 6b79 7065 3a3f  
08389: 5374 77c3 b372 7a20 4b6c 6f6e 6965 3c2f  Stw..rz Klonie
08399: 613e 0050 6f6b 61c5 bc20 c59b 7769 6174  a>.Poka.. ..wiat
083a9: 7520 7377 c3b3 6a20 5765 654d 6565 2e3c  u sw..j WeeMee.<

quindi strings mi fornisce l'indirizzo corretto, mentre grep no!
Errata corrige: (col grep aggiornato funziona invece)
Ne parlo con Mario Pascucci e lui mi suggerisce questa soluzione al dilemma, ossia che grep ha tutto un altro modo di ragionare con i caratteri e potrebbe interpretare erroneamente i caratteri di controllo
e soprattutto fare confusione con i caratteri multibyte, ossia interpretare sequenze di caratteri come multibyte, quando invece sono tutt'altro, e contarli come uno solo.

Un mistero è risolto! 
Ma su questi due strumenti NON ho finito di lavorarci, quindi, armato di cronometro ho fatto questo esperimento:

grep -iaob mustafa /cygdrive/c/immaginidd/barbuto.dd
tempo: 52 secondi e 50 centesimi - offset corretto 113917010

$ strings -t d /cygdrive/c/immaginidd/barbuto.dd | grep -i mustafa
113917010 tuo fratello Mustafa
tempo: 29 secondi e 84 centesimi - offset corretto 113917010

Insomma strings in pipe con grep è molto più veloce (il 51% in più).

Sempre consultandomi con Mario, mi suggerisce una spiegazione, che avevo intuito anch'io e che fa capire la potenza dell'operatore "pipe" (|) e di Linux.
Le ragioni della lentezza sono molteplici, ma una su tutte: 
strings ha un algoritmo infinitamente più semplice e veloce di grep, e la quantità di dati che estrae è esigua, per cui il secondo grep, il cui input è generato da strings, ha molto meno input da esaminare.

Per avere conferma di ciò, basta mandare l'output di strings su un file, e vedere che è immensamente più piccolo del file intero su cui strings ha lavorato.
inoltre ci sono altre ragioni, fra cui il fatto che grep è costruito per cercare in file di testo, suddiviso in righe, e con un set di caratteri ben definito, e passsandogli un binario, come appunto un'immagine dd, non è che lo aiuti molto. 
Strings invece produce un output molto vicino a quello su cui grep offre le prestazioni migliori.

In sostanza, strings estrae le stringhe da un file binario e passa il suo output in pipe a grep, che opererà la ricerca della parola "mustafa", su un output testuale e ridotto, sfruttando al massimo la sua potenza.

La stessa sperimentazione la si può fare usando queste immagini.

Nanni Bassetti