• Non ci sono risultati.

Bilancio sull’overhead di una chiamata di sistema

6.4 Valutazione delle performance

6.4.1 Bilancio sull’overhead di una chiamata di sistema

In base all’analisi appena fatta, si pu`o calcolare l’overhead associato ad ogni chiamata di sistema come:

Cint+ Cgret+ Ctstat+ Ccrypt+ Cdecrypt

In prima approssimazione, i primi tre valori , ossia Cint, Cgret, Ctstat, possono essere considerati come fissi ed i test effettuati dimostrano che la loro somma `e di 52 + 81 + 4 = 137µsec. A questo costo fisso occorre sommare poi il costo variabile dato da Ccrypt e Cdecrypt, che dipender`a dal numero e dalle dimensioni degli unit block contenuti nello state block terminato e da eseguire, e dalle loro dimensioni.

Riprendendo l’esempio precedente, nel caso di state block composti da un unit block da 1 kbyte, i tempi sono i seguenti:

Ccrypt+ Cdecrypt = 103 + 103 = 206µsec utilizzando DES Ccrypt+ Cdecrypt = 89 + 89 = 178µsec utilizzando Blowfish

Ccrypt+ Cdecrypt= 60 + 60 = 120µsec utilizzando One Time Pad appros-simato con generatore lineare congruente

6.4 Valutazione delle performance 86

Avendo dunque dei costi totali di:

Ctot = 137 + 206 = 343µsec utilizzando DES Ctot = 137 + 178 = 315µsec utilizzando Blowfish

Ctot = 137 + 120 = 257µsec utilizzando One Time Pad approssimato con generatore lineare congruente

Ctot = 137 + 0 = 137µsec nel caso si decida di non far uso di cifratura

Questi costi dovranno essere sommati al costo base di ciascuna chiamata di sistema che, a sua volta dipende dalla chiamata utilizzata di volta in volta.

Di seguito vengono riportati i costi di tre comuni chiamate di sistema:

time : 2µsec open : 3µsec

write(1kbyte) : 7µsec

Libreria di introspezione

La libreria di introspezione viene utilizzata dal processo manager per map-pare, nel proprio spazio di memoria virtuale, indirizzi di memoria virtuali appartenenti al processo offuscato, in modo tale da poter manipolare il loro contenuto. Tuttavia allo stato attuale la libreria soffre di un problema che causa una degradazione sensibile delle prestazioni del sistema. Il problema `e il seguente: se mappo un indirizzo A e successivamente un indirizzo B, dal momento in cui ho mappato B, l’indirizzo A e gli indirizzi che fanno parte della medesima pagina non sono pi`u accessibili. Per potervi di nuovo acce-dere, devo mappare di nuovo A. Questo crea chiaramente una degradazione, poich`e gran parte delle pagine a cui si deve accedere vengono riusate e invece di poter riutilizzare il lavoro gi`a fatto, `e necessario pagare di nuovo il costo

6.4 Valutazione delle performance 87

di una map e successivamente anche quello di una unmap in modo da evitare errori alla futura rimappatura della stessa pagina.

Dai test effettuati si `e osservato che il costo di una map `e di 37µsec, e quello di una unmap `e di 4µsec.

Di seguito verranno analizzati i costi delle varie fasi viste in precedenza, in modo tale da darne una nuova valutazione nel caso il problema alla libreria non fosse presente nel caso in cui le pagine a cui si vuole accedere siano gi`a state mappate in precedenza:

1. intercettazione delle chiamate di sistema : questa fase `e carat-terizzata da una map e una unmap, che corrispondono all’indirizzo di memoria della variabile si sincronizzazione associata al canale di comu-nicazione. Dunque si avrebbe un costo Cint= 52 − (Cmap+ Cunmap) = 52 − (37 + 4) = 11µsec.

2. individuazione del return address : questa fase `e caratterizzata in media da due map, che corrispondono alle due pagine contenenti le aree del kernel stack e dello user stack da analizzare. Inoltre c’`e la unmap della pagina del kernel stack. La unmap dello user stack avverr`a nella fase successiva. Dunque si avrebbe un costo Cgret = 81 − (2 · Cmap+ Cunmap) = 81 − (2 · 37 + 4) = 81 − 78 = 4µsec.

3. transizione di stato : questa fase `e caratterizzata dalla unmap del-la pagina appartenente allo user stack mappato neldel-la fase precedente.

Dunque si avrebbe un costo Ctstat = 4 − Cunmap = 4 − 4 = 0µsec. In questo caso dunque il costo residuo `e dell’ordine dei nano-secondi.

4. fasi di cifratura e decifratura: questa fase `e caratterizzata da una map e da una unmap per quanto riguarda la variabile “s”, ossia il costo fisso di gestione per ogni unit block. Dunque, il nuovo valore della variabile

`

e s = 41 − (Cmap+ Cunmap) = 41 − (37 + 4) = 0µsec. In questo caso s ha

6.4 Valutazione delle performance 88

un valore dell’ordine dei nano-secondi. Nel caso dell’esempio in cui sia lo state block terminato che lo state block da eseguire siano composti da uno unit block di 1 kbyte, il nuovo costo di cifratura e decifratura sar`a:

Ccrypt = Cdecrypt= 62µsec per il Des Ccrypt = Cdecrypt= 48µsec per Blowfish

Ccrypt = Cdecrypt = 19µsec per One Time Pad approssimato con gene-ratore lineare congruente.

Dunque in questo caso, l’overhead fisso associato ad ogni chiamata di sistema risulterebbe:

Cint+ Cgret+ Ctstat = 11 + 4 + 0 = 15µsec

a questo occorre sommare il costo variabile della cifratura e decifratura che nel caso di state block composti da uno unit block delle dimensioni di 1 kbyte sarebbe:

Ccrypt+ Cdecrypt = 62 + 62 = 124µsec utilizzando DES Ccrypt+ Cdecrypt = 48 + 48 = 96µsec utilizzando Blowfish

Ccrypt+ Cdecrypt= 19 + 19 = 38µsec utilizzando One Time Pad approssi-mato con generatore lineare congruente

Abbiamo quindi i seguenti costi totali:

Ctot = 15 + 124 = 139µsec utilizzando DES Ctot = 15 + 96 = 111µsec utilizzando Blowfish

Ctot = 15 + 38 = 53µsec utilizzando One Time Pad approssimato con generatore lineare congruente

Ctot = 15 + 0 = 15µsec se non si applica la cifratura

6.4 Valutazione delle performance 89

Figura 6.1: (1) l’overhead attuale. (2) l’overhead se la libreria permettesse di riutilizzare gli indirizzi delle pagine gi`a mappate

Come si pu`o osservare dal grafico in Fig. 6.1, la differenza di overhead rispetto al caso attuale `e significativa.

6.4.2 Considerazioni sull’overhead globale

Non `e semplice valutare in generale le prestazioni del sistema, poich`e l’ove-rhead `e fortemente dipendente dalle caratteristiche di ciascuna applicazione che deve essere protetta con l’architettura. Tali caratteristiche riguardano:

• la distribuzione delle chiamate di sistema;

• le dimensioni (e il numero) degli unit block all’interno di ciascun state block ed il numero di istruzioni eseguite in un unit block;

6.4 Valutazione delle performance 90

La distribuzione delle chiamate di sistema `e importante, poich`e sono pro-prio le chiamate ad innescare i meccanismi di gestione, e dunque l’overhead `e direttamente dipendente dal loro numero ed anche dal livello di offuscamento.

Le dimensioni degli state block, anch’essi funzione della distribuzione delle chiamate di sistema, determinano inoltre la dimensione di dati da cifrare. Di conseguenza, minore `e il rapporto tra il codice effettivamente eseguito ad un dato istante e la dimensione dello state block d’appartenenza, maggiore sar`a l’overhead.

Un esempio di caso ottimo per minimizzare i costi `e quello di uno state block costituito da un costrutto “while” il cui corpo sia eseguito numerose volte, con una chiamata di sistema appena all’esterno del ciclo che determina la fine del blocco.

while(guard){

code;

. . code;

}

syscall();

In un caso come questo, all’aumentare del numero dei cicli, l’overhead tende a zero.

Un esempio di caso pessimo `e il seguente:

if(cond){

code;

6.4 Valutazione delle performance 91

. . code;

}

syscall();

Questo blocco di codice pu`o essere considerato un caso sfavorevole, da un punto di vista delle prestazioni, se il ramo “if” contiene un numero molto grande di istruzioni ma il predicato `e falso. Ci`o genera un overhead elevato, poich`e il codice realmente eseguito `e solo la chiamata di sistema, ma si `e dovuto pagare un costo elevato per la cifratura/decifratura degli state block.

Un metodo per stimare le prestazioni generali del sistema, `e ovviamente quello di valutare i tempi per eseguire alcune applicazioni reali. Questo al momento non `e possibile perch`e questa tesi `e focalizzata sulla progettazione dell’architettura del sistema di offuscamento e sullo sviluppo del sistema a tempo d’esecuzione. Lo sviluppo di un compilatore che possa generare binari adatti a tale architettura avver`a successivamente.

Capitolo 7 Conclusioni

Questa tesi ha presentato una nuova architettura per offuscare il programma di un processo. L’architettura `e basata su un ambiente a macchine virtua-li, in cui una macchina esegue il processo offuscato, e un’altra esegue un processo che gestisce l’offuscamento del processo precedente (il “manager”).

La virtualizzazione `e stata utilizzata per ottenere una maggiore robustezza e separazione tra l’ambiente d’esecuzione e quello di gestione. Le principali tecniche di offuscamento implementate dall’architettura riguardano la parti-zione del controllo di flusso tra due macchine virtuali e la cifratura del codice da eseguire. Entrambe le tecniche sfruttano una strutturazione ad hoc del codice del processo. Tale strutturazione prevede che il codice sia suddiviso in blocchi delimitati dalle invocazioni al sistema operativo. L’eseguibile del pro-cesso contiene il codice dei blocchi, ma non le informazioni che li collegano;

queste verranno mantenute nascoste sull’altra macchina virtuale, che si oc-cuper`a di gestire le transizioni del flusso d’esecuzione tra la fine di un blocco di codice e l’inizio del blocco successivo. La cifratura del codice riguarda sia il disco fisso che la memoria, ed `e associata alla decomposizione in blocchi del codice. In memoria, durante l’esecuzione del processo, solo il blocco di codice momentaneamente attivo `e in chiaro, mentre gli altri rimangono cifrati. Le

93

operazioni di cifratura e decifratura vengono effettuate dal processo manager eseguito dall’altra macchina virtuale, che incapsula quindi le chiavi di cifra-tura. Il processo manager viene eseguito ogni volta che viene invocata una chiamata di sistema dal processo offuscato ed implementa le sue operazioni di gestione, in particolare la manipolazione dello stato del processo sull’altra macchina, applicando la tecnica d’introspezione della memoria.

Il prototipo realizzato ha dimostrato la fattibilit`a dell’architettura propo-sta. I test effettuati hanno permesso di valutare l’overhead associato a cia-scuna chiamata di sistema e dimostrano come l’effettiva usabilit`a dell’archi-tettura in termini di efficienza, dipenda dalla futura evoluzione della libreria d’introspezione utilizzata.

Questa tesi si `e concentrata sulla progettazione dell’architettura di offu-scamento proposta e sulla realizzazione di un prototipo del sistema a tempo d’esecuzione. I possibili sviluppi futuri riguardano l’implementazione di un compilatore in grado di produrre dei binari adatti all’eseccuzione sull’archi-tettura attualmente implementata, in modo da soddisfare le specifiche sulla strutturazione del codice.

Appendice A - Codice

manager.c

#include <s t d i o . h>

#include < s t d l i b . h>

#include < s t r i n g . h>

#include <t i m e . h>

#include <x e n c t r l . h>

#include <xen / i o / xenbus . h>

#include <x s . h>

#include <l i n u x / k e r n e l . h>

#include <l i n u x / u n i s t d . h>

#include <s y s / s t a t . h>

#include <asm/ p o s i x t y p e s . h>

#include <l i n u x / t y p e s . h>

#include ” p a r s e g r a p h . h”

#include ” p a r s e c o d e . h”

#include ” t v m m i n t r o s f u n . h”

#define p a g e a d d r ( a ) ( ( ( unsigned long ) ( a ) ) & 0xFFFFF000 )

#define munmap page ( p t r ) (munmap ( ( void ∗ ) p a g e a d d r ( ( p t r ) ) , XC PAGE SIZE ) )

95

#define NO TLB 1

#define PRINT 1

typedef k e r n e l u i d 3 2 t q i d t ;

s t a t i c i n t x c h a n d l e = −1;

s t a t i c u i n t 3 2 t domid = 0 ; s t a t i c unsigned long p a g a d d r ;

void ∗ p a g e m a p p e d a d d r e s s ;

void ∗ e s p p r o c e s s l o c a t i o n ; void ∗ e b p p r o c e s s l o c a t i o n ;

FILE ∗ l o g F i l e ;

StateGraph ∗ sGraph = NULL ;

CodeSegment ∗ i nf oC od eS eg m en t = NULL ; unsigned i n t c u r r e n t s t a t e = 0 ; unsigned i n t n e x t s t a t e ;

bool inCodeSegment ( unsigned i n t a d d r e s s ) { i f ( i nf oC od eS e gm en t == NULL) return f a l s e ;

i f ( ( a d d r e s s >= infoCodeSegment−>s t a r t a d d r e s s ) && ( a d d r e s s <=

infoCodeSegment−>e n d a d d r e s s ) ) return true ;

e l s e

return f a l s e ; }

void ∗ g e t R e t u r n A d d r e s s 2 ( ) {

96

PROT READ | PROT WRITE, KERNEL PGD) ; b a s e p o i n t e r k e r n e l c o n t e n t = ∗ ( u i n t 3 2 t ∗ )

97

98 PROT READ | PROT WRITE, PROCESS PGD) ;

b a s e p o i n t e r c o n t e n t = ∗ ( u i n t 3 2 t ∗ )

99

100 PROT READ | PROT WRITE, KERNEL PGD) ;

b a s e p o i n t e r k e r n e l c o n t e n t = ∗ ( u i n t 3 2 t ∗ )

101

102 PROT READ | PROT WRITE, PROCESS PGD) ;

b a s e p o i n t e r c o n t e n t = ∗ ( u i n t 3 2 t ∗ )

103

104

void ∗ u B l o c k i n i t i a l a d d r e s s m a p p e d = tv mapmem domu ( x c h a n d l e , 0 , domid , ( void ∗ ) ( ub . i n i t i a l a d d r e s s ) , PROT READ | PROT WRITE, PROCESS PGD) ;

unsigned char e n c r y p t e d C o d e [ ub . s i z e ] ;

105 PROT READ | PROT WRITE, PROCESS PGD) ;

unsigned char d e c r y p t e d C o d e [ ub . s i z e ] ;

106 PROT READ | PROT WRITE, PROCESS PGD) ;

unsigned char e n c r y p t e d C o d e [ ub . s i z e ] ;

107 PROT READ | PROT WRITE, PROCESS PGD) ;

unsigned char d e c r y p t e d C o d e [ ub . s i z e ] ;

108

109

void ∗ u B l o c k i n i t i a l a d d r e s s m a p p e d = tv mapmem domu ( x c h a n d l e , 0 , domid , ( void ∗ ) ( ub . i n i t i a l a d d r e s s ) , PROT READ | PROT WRITE, PROCESS PGD) ;

unsigned char e n c r y p t e d C o d e [ ub . s i z e ] ;

110

void ∗ u B l o c k i n i t i a l a d d r e s s m a p p e d = tv mapmem domu ( x c h a n d l e , 0 , domid , ( void ∗ ) ( ub . i n i t i a l a d d r e s s ) , PROT READ | PROT WRITE, PROCESS PGD) ;

unsigned char d e c r y p t e d C o d e [ ub . s i z e ] ;

111

c r y p t d e c r y p t S O T P ( ) ; }

E x i t P o i n t ∗ f i n d E x i t P o i n t ( S t a t e ∗ s t , unsigned i n t r e t a d d r e s s , void ∗ r e t a d d r e s s l o c a t i o n ) {

E x i t P o i n t ∗ e p t = ( s t −>e x i t P o i n t H T ) [ r e t a d d r e s s % 1 6 ] ;

i f ( e p t == NULL) return NULL ;

i f ( ept−>r e t u r n a d d r e s s == r e t a d d r e s s ) { i f ( ept−>r o o t r e t u r n a d d r e s s == 0 ) {

return e p t ; }

e l s e { /∗ r o o t r e t u r n a d d r e s s c h e c k ∗/ } }

e l s e {

while ( ept−>n e x t != NULL) { e p t = ept−>n e x t ;

i f ( ept−>r e t u r n a d d r e s s == r e t a d d r e s s ) { i f ( ept−>r o o t r e t u r n a d d r e s s == 0 ) {

return e p t ; }

e l s e { /∗ r o o t r e t u r n a d d r e s s c h e c k ∗/ } }

}

return NULL ; }

}

i n t main ( i n t a r g c , char ∗∗ a r g v ) {

s t r u c t x s h a n d l e ∗ x s ; /∗ x e n s t o r e h a n d l e r ∗/

112

113

114

115

116

117

118

memcpy ( p a g e m a p p e d a d d r e s s , &guard , s i z e o f ( i n t ) ) ; x c d o m a i n u n p a u s e ( x c h a n d l e , domid ) ;

#i f NO TLB

munmap page ( p a g e m a p p e d a d d r e s s ) ;

#endif }

x c e v t c h n u n m a s k ( x c e h a n d l e , l o c a l p o r t ) ; x c e v t c h n c l o s e ( x c e h a n d l e ) ;

x c i n t e r f a c e c l o s e ( x c h a n d l e ) ; return 0 ;

}

util.h

#include <math . h>

#include <u n i s t d . h>

#include < s t r i n g . h>

#include <s t d i o . h>

#include < s t d l i b . h>

#include < f c n t l . h>

#include < g l i b . h>

#include <s y s / t i m e . h>

#include <t i m e . h>

char ∗ t r i m ( char ∗ ) ;

unsigned i n t s t r i n g T o 3 2 b i t X I n t ( char ∗ ) ;

unsigned long s t r i n g T o l o n g ( char ∗ ) ;

119

util.c

#include ” u t i l . h”

char ∗ t r i m ( char ∗ s t r ) {

i f ( s t r == NULL) return NULL ; i n t s t r S i z e = s t r l e n ( s t r ) ; i f ( s t r S i z e == 0 ) return NULL ; i n t i = 0 ;

i n t i n i t W h i t e S p a c e s = 0 ; i n t endWhiteSpaces = 0 ; while ( i < s t r S i z e ) {

i f ( ( s t r [ i ] == ’ ’ ) | | ( s t r [ i ] == ’ ’ ) ) i n i t W h i t e S p a c e s ++;

e l s e break ; i ++;

}

i = s t r S i z e −1;

while ( i >=0){

i f ( ( s t r [ i ] == ’ ’ ) | | ( s t r [ i ] == ’ ’ ) ) endWhiteSpaces++;

e l s e break ; i −−;

}

i n t n e w S t r S i z e = s t r S i z e − ( i n i t W h i t e S p a c e s + endWhiteSpaces ) ; i f ( n e w S t r S i z e == 0 ) return NULL ;

char ∗ trimmedStr = m a l l o c ( ( n e w S t r S i z e +1) ∗ s i z e o f ( char ) ) ; i = 0 ;

while ( i < n e w S t r S i z e ) {

trimmedStr [ i ] = s t r [ i n i t W h i t e S p a c e s + i ] ; i ++;

120

121

122

123

124

d e f a u l t : // i l l e g a l v a l u e f r e e ( s t r ) ;

return 2 ; }

totNumber += number ∗ pow ( 1 0 , c y c l e ) ; }

f r e e ( s t r ) ;

return totNumber ; }

parse graph.h

#include ” u t i l . h”

typedef s t r u c t {

unsigned i n t r e t u r n a d d r e s s ; unsigned i n t r o o t r e t u r n a d d r e s s ; unsigned i n t n e x t s t a t e i d ;

void ∗ n e x t ; // E x i t P o i n t ∗ } E x i t P o i n t ;

typedef s t r u c t { E x i t P o i n t ∗ ep ;

void ∗ n e x t ; // E x i t P o i n t R e f ∗ } E x i t P o i n t R e f ;

typedef s t r u c t { E x i t P o i n t ∗ head ; E x i t P o i n t ∗ c u r r e n t ;

125

126

typedef s t r u c t {

S t a t e ∗ s t a t e V e c t o r ; unsigned i n t l e n g t h ; } StateGraph ;

typedef s t r u c t { S t a t e L i s t ∗ s t a t e L ; g c h a r ∗ l a s t t a g ; } ParserGraph ;

void p a r s i n g g e t e l e m e n t ( GMarkupParseContext ∗ , const g c h a r ∗ , const g c h a r ∗ ∗ , const g c h a r ∗ ∗ , g p o i n t e r , GError ∗ ∗ ) ;

void p a r s i n g g e t v a l u e ( GMarkupParseContext ∗ , const g c h a r ∗ , g s i z e , g p o i n t e r , GError ∗ ∗ ) ;

void d e s t r o y p a r s e r ( g p o i n t e r ) ;

StateGraph ∗ p a r s e g r a p h ( char ∗ ) ;

StateGraph ∗ setupGraph ( S t a t e L i s t ∗ ) ;

void p r i n t S t a t e L i s t ( S t a t e L i s t ∗ ) ;

parse graph.c

#include ” p a r s e g r a p h . h”

127

128

129

130

131

132

GMarkupParser p a r s e r ;

GMarkupParseContext ∗ c o n t e x t ; ParserGraph b u f f e r ;

b u f f e r . s t a t e L = NULL ;

memset ( &p a r s e r , 0 , s i z e o f ( GMarkupParser ) ) ; p a r s e r . s t a r t e l e m e n t = p a r s i n g g e t e l e m e n t ; p a r s e r . e n d e l e m e n t = NULL ;

p a r s e r . t e x t = p a r s i n g g e t v a l u e ;

memset ( &b u f f e r , 0 , s i z e o f ( ParserGraph ) ) ;

c o n t e x t = g m a r k u p p a r s e c o n t e x t n e w ( &p a r s e r , 0 , &b u f f e r , d e s t r o y p a r s e r ) ;

i n t num = 0 ;

i n t b u f f S i z e T e m p = 1 0 0 ;

char ∗ tempBuf = m a l l o c ( b u f f S i z e T e m p ∗ s i z e o f ( char ) ) ; i n t f d = open ( f i l e , O RDONLY) ;

i f ( f d == −1) return NULL ;

while ( ( num = r e a d ( fd , tempBuf , b u f f S i z e T e m p ) ) > 0 ) {

g m a r k u p p a r s e c o n t e x t p a r s e ( c o n t e x t , tempBuf , num , NULL )

; }

g m a r k u p p a r s e c o n t e x t e n d p a r s e ( c o n t e x t , NULL ) ; g m a r k u p p a r s e c o n t e x t f r e e ( c o n t e x t ) ;

return setupGraph ( b u f f e r . s t a t e L ) ; }

void p r i n t S t a t e L i s t ( S t a t e L i s t ∗ s l ) {

133

134

135

136

137

typedef s t r u c t { unsigned i n t i d ;

unsigned i n t i n i t i a l a d d r e s s ; unsigned i n t s i z e ;

void ∗ n e x t ; // UnitBlockTemp } UnitBlockTemp ;

typedef s t r u c t {

unsigned i n t s t a r t a d d r e s s ; unsigned i n t e n d a d d r e s s ;

unsigned i n t e n c r y p t i o n m e t h o d ; UnitBlockTemp ∗ head ;

UnitBlockTemp ∗ c u r r e n t ; unsigned i n t l e n g t h ; } CodeSegmentUnitBlockList ;

typedef s t r u c t {

C o d e S e g m e n t U n i t B l o c k L i s t ∗ c o d e S e g ; g c h a r ∗ l a s t t a g ;

} P a r s e r C o S e g ;

void g e t e l e m e n t C o S e g ( GMarkupParseContext ∗ , const g c h a r ∗ , const g c h a r ∗ ∗ , const g c h a r ∗ ∗ , g p o i n t e r , GError ∗ ∗ ) ;

void g e t v a l u e C o S e g ( GMarkupParseContext ∗ , const g c h a r ∗ , g s i z e , g p o i n t e r , GError ∗ ∗ ) ;

void d e s t r o y p a r s e r C o S e g ( g p o i n t e r ) ;

138

CodeSegment ∗ p a r s e C o S e g ( char ∗ ) ;

void getKeysDES ( CodeSegment ∗ ) ;

void getKeysBF ( CodeSegment ∗ ) ;

void getKeysSOTP ( CodeSegment ∗ ) ;

CodeSegment ∗ s e t u p C o d e S e g m e n t B l o c k s ( C o d e S e g m e n t U n i t B l o c k L i s t ∗ ) ;

void p r i n t C o d e S e g m e n t B l o c k s ( CodeSegment ∗ ) ;

parse code.c

#include ” p a r s e c o d e . h”

void g e t e l e m e n t C o S e g ( GMarkupParseContext ∗ c o n t e x t , const g c h a r ∗ element name ,

const g c h a r ∗∗ a t t r i b u t e n a m e s , const g c h a r ∗∗

a t t r i b u t e v a l u e s ,

g p o i n t e r u s e r d a t a , GError ∗∗ e r r o r ) {

P a r s e r C o S e g ∗ b u f f e r ;

b u f f e r = ( P a r s e r C o S e g ∗ ) u s e r d a t a ; i f ( b u f f e r −>l a s t t a g != NULL )

f r e e ( b u f f e r −>l a s t t a g ) ;

b u f f e r −>l a s t t a g = s t r d u p ( element name ) ;

i f ( strcmp ( element name , ” c o d e s e g m e n t ” ) == 0 ) {

139

140

141

142

b u f f e r . c o d e S e g = NULL ;

memset ( &p a r s e r , 0 , s i z e o f ( GMarkupParser ) ) ; p a r s e r . s t a r t e l e m e n t = g e t e l e m e n t C o S e g ;

p a r s e r . e n d e l e m e n t = NULL ; p a r s e r . t e x t = g e t v a l u e C o S e g ;

memset ( &b u f f e r , 0 , s i z e o f ( P a r s e r C o S e g ) ) ;

c o n t e x t = g m a r k u p p a r s e c o n t e x t n e w ( &p a r s e r , 0 , &b u f f e r , d e s t r o y p a r s e r C o S e g ) ;

i n t num = 0 ;

i n t b u f f S i z e T e m p = 1 0 0 ;

char ∗ tempBuf = m a l l o c ( b u f f S i z e T e m p ∗ s i z e o f ( char ) ) ; i n t f d = open ( f i l e , O RDONLY) ;

i f ( f d == −1) return NULL ;

while ( ( num = r e a d ( fd , tempBuf , b u f f S i z e T e m p ) ) > 0 ) {

g m a r k u p p a r s e c o n t e x t p a r s e ( c o n t e x t , tempBuf , num , NULL )

; }

g m a r k u p p a r s e c o n t e x t e n d p a r s e ( c o n t e x t , NULL ) ; g m a r k u p p a r s e c o n t e x t f r e e ( c o n t e x t ) ;

f r e e ( tempBuf ) ;

return s e t u p C o d e S e g m e n t B l o c k s ( b u f f e r . c o d e S e g ) ; }

void getKeysDES ( CodeSegment ∗ c s ) { i n t f d ;

i n t keysNumber = c s −>uBlockNumber ; DES cblock key ;

143

i n t keysNumber = c s −>uBlockNumber ; unsigned char k e y d a t a [ 1 7 ] ;

BF KEY∗ key ;

144

void getKeysSOTP ( CodeSegment ∗ c s ) {

i n t f d ;

i n t keysNumber = c s −>uBlockNumber ;

145

146

147

c s −>u B l o c k V e c t o r = ub ;

f r e e ( c s u b ) ;

i f ( c s −>e n c r y p t i o n m e t h o d == DES) { getKeysDES ( c s ) ;

}

e l s e i f ( c s −>e n c r y p t i o n m e t h o d == BLOWFISH) { getKeysBF ( c s ) ;

}

e l s e i f ( c s −>e n c r y p t i o n m e t h o d == SOTP) { getKeysSOTP ( c s ) ;

}

return c s ; }

void d e s t r o y p a r s e r C o S e g ( g p o i n t e r d a t a ) { P a r s e r C o S e g ∗ b u f f e r ;

b u f f e r = ( P a r s e r C o S e g ∗ ) d a t a ; i f ( b u f f e r −>l a s t t a g != NULL )

f r e e ( b u f f e r −>l a s t t a g ) ; }

void p r i n t C o d e S e g m e n t B l o c k s ( CodeSegment ∗ c s ) { i f ( c s == NULL) return ;

p r i n t f ( ” s t a r t a d d r e s s = %x\n” , c s −>s t a r t a d d r e s s ) ; p r i n t f ( ” e n d a d d r e s s = %x\n” , c s −>e n d a d d r e s s ) ;

p r i n t f ( ” e n c r y p t i o n m e t h o d = %d\n” , c s −>e n c r y p t i o n m e t h o d ) ; p r i n t f ( ” B l o c k s number = %d\n” , c s −>uBlockNumber ) ;

U n i t B l o c k ∗ ub = c s −>u B l o c k V e c t o r ; i n t i = 0 ;

148

f o r ( i = 0 ; i < c s −>uBlockNumber ; i ++){

unsigned i n t pos = i ;

p r i n t f ( ” B l o c k i d = %d\n” , ( ub+pos )−>i d ) ;

p r i n t f ( ” i n i t i a l a d d r e s s = %x\n” , ( ub+pos )−>

i n i t i a l a d d r e s s ) ;

p r i n t f ( ” s i z e = %x\n” , ( ub+pos )−> s i z e ) ;

p r i n t f ( ” i s C r y p t e d = %d\n” , ( ub+pos )−>i s C r y p t e d ) ; }

}

keys generator.c

#include <s y s / t y p e s . h>

#include <s y s / s t a t . h>

#include < f c n t l . h>

#include <u n i s t d . h>

#include < s t r i n g . h>

#include <o p e n s s l / d e s . h>

#include <o p e n s s l / b l o w f i s h . h>

#include <o p e n s s l / rand . h>

void genDesKeys ( i n t num) { DES cblock key ;

DES cblock i v e c ;

i n t f d= open ( ” k e y s . k” , O WRONLY| O CREAT | O TRUNC, 0 6 6 6 ) ; i f ( f d == −1){

p r i n t f ( ” E r r o r c r e a t i n g k e y s . k . \ n” ) ; e x i t ( 1 ) ;

149

150

e x i t ( 1 ) ; }

i n t i = 0 ;

f o r ( i = 0 ; i < num ; i ++){

RAND bytes ( k e y d a t a , 1 2 ) ; w r i t e ( fd , k e y d a t a , 1 2 ) ; }

c l o s e ( f d ) ; }

/∗

Takes a s f i r s t argument t h e t y p e o f e n c r y p t i o n , a s s e c o n d argument t h e number o f k e y s ( and i v ) t o c r e a t e , and a s t h i r d argument a s t r i n g t o s e e d t h e random number g e n e r a t o r

∗/

i n t main ( i n t a r g c , char ∗ a r g v [ ] ) {

i n t numberOfKeys = 0 ; char ∗ e n c r y p t i o n t y p e ; char ∗ s t r ;

i f ( a r g c != 4 ) {

p r i n t f ( ”Number o f arguments n o t v a l i d ! \ n” ) ; e x i t ( 1 ) ;

}

e n c r y p t i o n t y p e = a r g v [ 1 ] ; numberOfKeys = a t o i ( a r g v [ 2 ] ) ;

i f ( numberOfKeys == 0 ) {

p r i n t f ( ” I n v a l i d number o f k e y s . ” ) ; return ( 1 ) ;

151

}

s t r = a r g v [ 3 ] ;

RAND seed ( s t r , s t r l e n ( s t r ) ) ;

i f ( strcmp ( e n c r y p t i o n t y p e , ”DES” ) == 0 ) genDesKeys ( numberOfKeys ) ;

e l s e i f ( strcmp ( e n c r y p t i o n t y p e , ”BF” ) == 0 ) genBFKeys ( numberOfKeys ) ;

e l s e i f ( strcmp ( e n c r y p t i o n t y p e , ”SOTP” ) == 0 ) genSOTPKeys ( numberOfKeys ) ;

e l s e

p r i n t f ( ”The t y p e o f e n c r y p t i o n s p e c i f i e d i s n o t v a l i d ! \ n” ) ; return 0 ;

}

elf encryptor.c

#include ” p a r s e c o d e . h”

i n t f d E l f F i l e ; char ∗ e l f F i l e ;

CodeSegment ∗ in f oC od eS eg m en t = NULL ;

i n t g e t C S O f f s e t ( char ∗ s t r ) { i n t strNumber = 0 ;

char s t r C S O f f s e t [ 1 0 ] ; i n t guard = TRUE;

i n t i = 0 ;

while ( guard ) {

152 unsigned i n t uBVecLen = infoCodeSegment−>uBlockNumber ; char f i l e C o d e E n c r y p t N a m e [ 3 0 0 ] ;

153

154

void encWithBF ( i n t t e x t S e g m e n t O f f s e t ) {

U n i t B l o c k ∗ uBlockVec = infoCodeSegment−>u B l o c k V e c t o r ; unsigned i n t uBVecLen = infoCodeSegment−>uBlockNumber ; char f i l e C o d e E n c r y p t N a m e [ 3 0 0 ] ;

155

156 unsigned i n t uBVecLen = infoCodeSegment−>uBlockNumber ; char f i l e C o d e E n c r y p t N a m e [ 3 0 0 ] ;

157

158

fdTmpFile= open ( tmpFile , O RDONLY) ; i f ( fdTmpFile == −1){

159

e x i t ( 1 ) ; }

t e x t S e g m e n t O f f s e t = g e t C S O f f s e t ( s t r ) ; s p r i n t f ( cmd , ”rm %s ” , t m p F i l e ) ;

syste m ( cmd ) ;

p r i n t f ( ” o f f s e t = %d\n” , t e x t S e g m e n t O f f s e t ) ; e n c r y p t E l f F i l e ( t e x t S e g m e n t O f f s e t ) ;

c l o s e ( f d E l f F i l e ) ; return ( 0 ) ;

}

Elenco delle figure

2.1 Compilazione vs Reverse Engineering . . . 8

2.2 (a) Codice originale. (b) Codice che utilizza una branch function. 10 2.3 (a) Codice originale. (b) Codice con trasformazioni if-then-goto. 14 2.4 Control flow appiattito sostituento i goto con uno switch. . . . 15

3.1 (a) unhosted vmm. (b) hosted vmm. . . 23

4.1 Esempio 1: rappresentazione del control flow graph . . . 42

4.2 Esempio 1: grafo degli state block . . . 44

4.3 Esempio 2: rappresentazione del control flow graph . . . 45

4.4 Esempio 2: grafo degli state block . . . 46

4.5 Esempio 3: rappresentazione del control flow graph . . . 47

4.6 Esempio 3: grafo degli state block . . . 48

5.1 Divisione del controllo di flusso . . . 50

5.2 Esempio di indeterminazione nel caso venga utilizzato il tipo di una chiamata di sistema come discriminante nel passaggio tra state block . . . 54

5.3 Architettura . . . 59

ELENCO DELLE FIGURE 161

5.4 Ricerca del return address . . . 65 6.1 (1) l’overhead attuale. (2) l’overhead se la libreria permettesse

di riutilizzare gli indirizzi delle pagine gi`a mappate . . . 89

Bibliografia

[BDF+03] Paul R. Barham, Boris Dragovic, Keir A. Fraser, Steven M.

Hand, Timothy L. Harris, Alex C. Ho, Evangelos Kotsovinos, Anil V. S. Madhavapeddy, Rolf Neugebauer, Ian A. Pratt, and Andrew K. Warfield. Xen 2002. Technical Report UCAM-CL-TR-553, University of Cambridge, Computer Laboratory, January 2003.

[BMST09] Fabrizio Baiardi, Dario Maggiari, Daniele Sgandurra, and Fran-cesco Tamberi. Psycotrace: Virtual and transparent monitoring of a process self. In Didier El Baz, Fran¸cois Spies, and Tom Gross, editors, PDP, pages 393–397. IEEE Computer Society, 2009.

[CTL97] Christian Collberg, Clark Thomborson, and Douglas Low. A taxonomy of obfuscating transformations. Technical Report 148, Department of Computer Sciences, The University of Auckland, July 1997.

[CTL98] Christian S. Collberg, Clark D. Thomborson, and Douglas Low.

Manufacturing cheap, resilient, and stealthy opaque constructs.

In POPL, pages 184–196, 1998.

BIBLIOGRAFIA 163

[KAH07] Prasad Kulkarni, Matthew Arnold, and Michael Hind. Dynamic compilation: the benefits of early investing. In Chandra Krintz, Steven Hand, and David Tarditi, editors, VEE, pages 94–104.

ACM, 2007.

[Lan92] William Landi. Undecidability of static analysis. LOPLAS, 1(4):323–337, 1992.

[LD03] Linn and Debray. Obfuscation of executable code to improve re-sistance to static disassembly. In SIGSAC: 10th ACM Conferen-ce on Computer and Communications Security. ACM SIGSAC, 2003.

[Mye81] E. W. Jr. Myers. A precise inter-procedural data flow algorithm.

In Conference record of the 8th ACM Symposium on Principles of Programming Languages (POPL), pages 219–230, 1981.

[SCK+93] R. L. Sites, A. Chernoff, M. B. Kirk, M. P. Marks, and S. G.

Robinson. Binary translation. Communications of the ACM, 36(2):69–81, February 1993.

[WHKD00] Chenxi Wang, Jonathan Hill, John Knight, and Jack Davidson.

Software tamper resistance: Obstructing static analysis of pro-grams. Technical Report CS-2000-12, Department of Computer Science, University of Virginia, May 12 2000. Tue, 30 May 2000 16:51:20 GMT.

Documenti correlati