Zoom Icon

Winamp 5.05 Code Injection

From UIC Archive

Winamp 5.05: Code Injection

Contents


Winamp 5.05 Code Injection
Author: Bender0
Email: Mips-email.png
Website: http://www.bender0.altervista.org/
Date: 31/10/2004 (dd/mm/yyyy)
Level: Quite hard
Language: Italian Flag Italian.gif
Comments:



Introduction

In un essay precedente ho parlato di winamp e della sua protezione; qui mi limito a dire che sono passato alla 5.05, più sicura (tanto usavo solo la modern skin ;) e, speriamo, definitiva. Nota bene: se chiudete un'occhio sugli offset qualsiasi versione 5.xx andrà benone.

È caldamente consigliato (vedi: obbligatorio) leggere l'essay di faina su AVI/MPEG/ASF/WMV Splitter.


Tools

Un compilatore e una buona api reference
Ollydbg o un debugger qualunque.


Link e Riferimenti

http://www.winamp.com per trovare winamp.


Notizie sul Programma

Winamp, sempre quello.


Essay

Ho scelto winamp come target di questo essay perché è diffuso e perché ne ho già parlato. In effetti questo essay non spiega come superare un certo tipo di protezione, ma come applicare una tecnica generica; quindi il target dell'essay avrebbe potuto essere un qualsiasi eseguibile.

Sappiamo già che winamp non è packato, quindi abbiamo campo libero per sperimentare senza troppi problemi; nonostante questo c'è da dire che la code injection è particolarmente d'aiuto contro i packers.

Cosa vuol dire code injection, al di là della traduzione letterale? Dicesi ;) code injection l'inserimento di codice (malvagio e/o benigno) nella memoria di un processo, in modo da alterare la sua normale esecuzione senza tuttavia modificare un solo byte del modulo associato al processo. IMHOIn My Humble Opinion è una tecnica molto elegante, senza contare i vantaggi che offre: il modulo eseguibile rimane intatto, quindi si eludono i crc sulla memoria fisica e con qualche accorgimento anche quelli sulla memoria del processo; se il file è packato si può agire direttamente sul codice già unpackato in memoria; si può inserire del codice, eseguirlo e ripulire tutto a totale insaputa del processo target; si possono fare insomma molte cose simpatiche soffrendo di meno vincoli.

Non mi soffermerò qui a parlare del debugging in generale; ne ho già parlato nell'essay su CloneDVD. Andiamo più nello specifico.

L'essay è diviso in quattro sezioni:

phase#1 :: simple injection
phase#2 :: thread injection
phase#3 :: triggered injection
phase#4 :: api hijacking

Simple Injection

~simple injection, #1

La forma più banale di code injection che mi possa immaginare. Carichiamo il target con CREATE_SUSPENDED, patchiamo qua e là ed eseguiamo. Questo metodo fallisce se è presente un check di integrità della memoria, certo anche quello si può patchare, ma cosa succede se il crc è in mezzo a un packer ingarbugliatissimo sotto layers e layers di crittazione? Possiamo dichiararci TFU (totally fucked up). Ma vediamo come si realizza una memory patch del genere.

Potremmo patchare qualsiasi cosa, ma voglio solo modificare una stringa in modo che sul balancing al posto di "Balance: Center" mostri "Balance: Bender" (lol). Quindi dobbiamo solo applicare una patch di quattro byte (dalla "B" alla 'd'), niente di più facile. Una piccola ricerca in memoria della stringa originale ci rivela che i byte da modificare si trovano a 459461. Ecco il sorgente: // phase1.cpp

  1. include <windows.h>
  2. include <stdio.h>

char filename[] = "winamp.exe"; char data[] = "Bend";

void main() {

 STARTUPINFO sI;
 PROCESS_INFORMATION pI;
 ZeroMemory( &sI, sizeof(sI) );
 sI.cb = sizeof(sI);
 ZeroMemory( &pI, sizeof(pI) );
 // creiamo il processo con CREATE_SUSPENDED
 // per fare le nostre modifiche
 CreateProcess(
 filename,
 NULL,NULL,NULL,
 false,
 DEBUG_ONLY_THIS_PROCESS|CREATE_SUSPENDED,
 NULL,NULL,
 &sI,&pI);
 HANDLE hProc = pI.hProcess;
 HANDLE hMainT = pI.hThread;
      
 // applichiamo la patch
 DWORD junk;
 WriteProcessMemory(hProc,(LPVOID)0x459461,(LPVOID)&data,sizeof(data),&junk);
 // ripristiniamo l'esecuzione
 ResumeThread(hMainT);
 // ci separiamo da winamp
 DebugActiveProcessStop(pI.dwProcessId);

} Compilo, avvio... azz non funziona. Le stringhe della modern skin sono contenute in essa, quindi cosa abbiamo modificato? Le stringhe della classic skin. Infatti con quella funziona :)

Thread Injection

~thread injection, #2

Tanto per contraddirmi, ora lavoriamo sulla protezione. Per i dettagli sulla protezione vi rimando (ancora) all'essay su winamp 5.04. La routine di check comincia a 444633, breakkiamo qui e ritorniamo; ci troviamo a 444619, dove possiamo vedere che la flag globale che controlla la registrazione è all'indirizzo 46A754. L'idea (stupida in sè, ma valida come esempio) è di creare un nostro thread all'interno del processo target, che setti a 3 (perchè 3? perché no? :) quella flag ogni secondo. Per controllare che il tutto funzioni possiamo attacharci con il debugger e breakkare sul nostro thread, o più semplicemente togliere il valore regkey dal registro (HKLM/Software/Nullsoft/Winamp) e vedere come winamp creda lo stesso di essere registrato.

Per prima cosa troviamo uno spazio libero per aggiungere il codice del nostro thread: all'indirizzo 452D00 abbiamo spazio a volontà. Allora a quell'indirizzo assembliamo: mov eax,46A754 mov dword ptr ds:[eax],3 push 3E8 call Sleep jmp 452D00 E vediamo che l'assembler genera questi byte, che poi scriveremo nella memoria di winamp:

0xB8,0x54,0xA7,0x46,0x00,0xC7,0x00,0x03,0x00,0x00,0x00,0x68,
0xE8,0x03,0x00,0x00,0xE8,0xD1,0xEE,0x9E,0x77,0xEB,0xE9

Una volta scritti questi byte dobbiamo creare un thread remoto, ovvero residente nel processo target. Per far questo abbiamo a disposizione l'api CreateRemoteThread; ecco sintassi e parametri: HANDLE CreateRemoteThread(

 HANDLE hProcess,
 LPSECURITY_ATTRIBUTES lpThreadAttributes,
 SIZE_T dwStackSize,
 LPTHREAD_START_ROUTINE lpStartAddress,
 LPVOID lpParameter,
 DWORD dwCreationFlags,
 LPDWORD lpThreadId

); hProcess
[in] handle del processo target.
lpThreadAttributes
[in] descrittore di sicurezza, un NULL andrà più che bene :).
dwStackSize
[in] size iniziale dello stack del thread, specifichiamo 0 come default.
lpStartAddress
[in] puntatore all'inizio del thread nella memoria del processo target.
lpParameter
[in] puntatore a un parametro da passare al thread, se non ci serve passiamo NULL.
dwCreationFlags
[in] flags di creazione. possiamo passare CREATE_SUSPENDED se vogliamo un thread fermo o 0 per avviarlo.
lpThreadId
[out] puntatore a una dword che riceve l'id del thread. se non ci serve passiamo NULL.

Dopo di ciò come al solito ci separiamo da winamp e ci terminiamo. Ecco il sorgente: // phase2.cpp

  1. include <windows.h>
  2. include <stdio.h>

char filename[] = "winamp.exe"; unsigned char data[] = {0xB8,0x54,0xA7,0x46,0x00,0xC7,

                       0x00,0x03,0x00,0x00,0x00,0x68,
                       0xE8,0x03,0x00,0x00,0xE8,0xD1,
                       0xEE,0x9E,0x77,0xEB,0xE9};

void main() {

 STARTUPINFO sI;
 PROCESS_INFORMATION pI;
 ZeroMemory( &sI, sizeof(sI) );
 sI.cb = sizeof(sI);
 ZeroMemory( &pI, sizeof(pI) );
 // creiamo il processo con CREATE_SUSPENDED
 // per fare le nostre modifiche
 CreateProcess(
   filename,
   NULL,NULL,NULL,
   false,
   DEBUG_ONLY_THIS_PROCESS|CREATE_SUSPENDED,
   NULL,NULL,
   &sI,&pI);
 HANDLE hProc = pI.hProcess;
 HANDLE hMainT = pI.hThread;
      
 // inseriamo il codice del nostro thread
 DWORD junk;
 WriteProcessMemory(hProc,(LPVOID)0x452d00,(LPVOID)&data,sizeof(data),&junk);
 // creaiamo il nostro thread
 CreateRemoteThread(hProc,NULL,0,(LPTHREAD_START_ROUTINE)0x452d00,NULL,0,NULL);
 // ripristiniamo l'esecuzione
 ResumeThread(hMainT);
 // ci separiamo da winamp
 DebugActiveProcessStop(pI.dwProcessId);

} Et voilà ;)

Triggered Injection

~triggered injection, #3

Per triggered injection intendo code injection "on request"; ovvero code injection applicata in risposta a degli eventi precisi. Ad esempio possiamo applicare la nostra memory patch appena un target packato si è unpackato in memoria, o rispondere a un nostro breakpoint per fare una piccola modifica e ripristinare il codice originale appena dopo la sua esecuzione.

In questo caso, per rispettare il carattere "teorico" dell'essay, faremo un'altra cosa inutile ma esplicativa. Proviamo a fare una modifica stealth: il target arriva al punto da patchare, noi interveniamo, il target esegue la patch, noi ripuliamo tutto.

Ci mettiamo dunque a traceare a partire dall'entry point. Lì troviamo le solite istruzioni di avvio, quindi steppiamo fino alla call a 41EFB0. Qui dentro c'è qualcosa di strano: ci sono delle call e dei loop che sembrano fare della crittografia, ma perché? Boh, steppiamoli tutti. Quando saremo a 41F0D2 vedremo che all'indirizzo 45A4B0 viene spostata una stringa, la seguente:
http://genghis.winamp.com/~christophe/egg.mp3
Uhm... bene, a quell'indirizzo strambo sotto winamp.com troviamo un mp3 di nome egg. Wheee! Abbiamo scoperto un uovo di pasqua :)
Se vi interessa nell'mp3 troverete 3:13 minuti di drum and bass contornati da urla di piacere erotico (da qui il titolo "Porn Egg").

Ma lasciamo perdere le uova di pasqua (è ottobre dopotutto) e torniamo a steppare. Poche linee più avanti viene chiamata la wsprintfA, che printa la stringa "Winamp 5.05": in seguito verrà usata (almeno) come nome nella taskbar (o come tooltip dell'icona del tray, se usate questa opzione). Ora supponiamo di voler cambiare la stringa: questa volta patchiamo il codice. Dobbiamo quindi patchare le istruzioni che caricano la stringa per constringere winamp a caricare la nostra. Vediamo come viene caricata: 0041F0D8 MOV EAX,DWORD PTR DS:[46B504] → carica l'indirizzo di "Winamp" + 10h [...] 0041F0EF SUB EAX,10 → toglie i 10h 0041F0F2 PUSH ECX → pusha "5.05" 0041F0F3 MOV DWORD PTR DS:[461AF0],EDX 0041F0F9 MOV EDX,DWORD PTR DS:[45A7FC] 0041F0FF PUSH EAX → pusha "Winamp" 0041F100 PUSH winamp.004590F4 → pusha la stringa di controllo formattazione, "%s %s" 0041F105 PUSH winamp.0046B820 → questo è il buffer che conterrà la stringa formattata 0041F10A MOV DWORD PTR DS:[46B504],EAX 0041F10F MOV DWORD PTR DS:[461AF8],EDX 0041F115 CALL DWORD PTR DS:[<&USER32.wsprintfA>] Sarà quindi sufficiente patchare all'indirizzo 41F0D8, assemblando un MOV EAX,indirizzo_della_nostra_stringa+10h. Riassumendo: fermiamo winamp all'entry point e scriviamo la nostra stringa in un'area vuota di memoria (452d00, come prima); settiamo un breakpoint a 41F0D8, dove poi andremo a patchare; quando scatta il breakpoint patchiamo; settiamo un breakpoint a 41F0DD; quando scatta il secondo breakpoint rimettiamo a posto il codice, facciamo ripartire winamp e ci separiamo.

Ecco il sorgente (se non capite qualcosa, LEGGETE IL TUTE DI FAINA): // phase3.cpp

  1. include <windows.h>
  2. include <stdio.h>

char filename[] = "winamp.exe"; unsigned char patchdata[] = {0xB8,0x10,0x2D,0x45,0x00,0xCC}; // MOV EAX,winamp.00452D10; int 3 unsigned char appname[] = "BENDamp";

bool BpWait(DWORD addr, DEBUG_EVENT &DebugEv) {

 bool searching = true;
 DWORD dwContinueStatus = DBG_CONTINUE;
 while (searching)
 {
   if (!WaitForDebugEvent(&DebugEv,INFINITE)) return false;
   if (DebugEv.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
   {
     if (DebugEv.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
       dwContinueStatus = DBG_CONTINUE;
     else dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
   }
   if (DebugEv.u.Exception.ExceptionRecord.ExceptionAddress == (void*)addr)
     searching = false;
   else
     ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus);
 }
 return true;

}

void main() {

 STARTUPINFO sI;
 PROCESS_INFORMATION pI;
 ZeroMemory( &sI, sizeof(sI) );
 sI.cb = sizeof(sI);
 ZeroMemory( &pI, sizeof(pI) );
 // creiamo il processo con CREATE_SUSPENDED
 // per fare le nostre modifiche
 CreateProcess(
   filename,
   NULL,NULL,NULL,
   false,
   DEBUG_ONLY_THIS_PROCESS|CREATE_SUSPENDED,
   NULL,NULL,
   &sI,&pI);
 HANDLE hProc = pI.hProcess;
 HANDLE hMainT = pI.hThread;
       
 DEBUG_EVENT DebugEv;
 // inseriamo la nostra stringa nella memoria del processo
 DWORD junk;
 WriteProcessMemory(hProc,(LPVOID)0x452d00,(LPVOID)&appname,sizeof(appname),&junk);
 // piazziamo il breakpoint e ripristiniamo l'esecuzione
 BYTE bp = 0xCC;
 WriteProcessMemory(hProc,(LPVOID)0x41F0D8,(LPVOID)&bp,1,&junk);
 ResumeThread(hMainT);
 // aspettiamo il breakpoint
 if (!BpWait(0x41F0D8,DebugEv)) exit (0);
 // patchiamo, riallineiamo eip e piazziamo il secondo breakpoint
 // (la patch sovrascrive anche il bp)
 WriteProcessMemory(hProc,(LPVOID)0x41F0D8,(LPVOID)&patchdata,sizeof(patchdata),&junk);
 CONTEXT tc;
 tc.ContextFlags = CONTEXT_ALL;
 GetThreadContext(hMainT,&tc);
 tc.Eip--;
 SetThreadContext(hMainT,&tc);
 ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, DBG_CONTINUE);
 ResumeThread(hMainT);
 // al secondo breakpoint risistemiamo tutto
 if (!BpWait(0x41F0DD,DebugEv)) exit (0);
 BYTE oldbyte = 0x8B;
 WriteProcessMemory(hProc,(LPVOID)0x41F0DD,(LPVOID)&oldbyte,1,&junk);
 tc.ContextFlags = CONTEXT_ALL;
 GetThreadContext(hMainT,&tc);
 tc.Eip--;
 SetThreadContext(hMainT,&tc);
 ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, DBG_CONTINUE);
 ResumeThread(hMainT);
 // ci separiamo da winamp
 DebugActiveProcessStop(pI.dwProcessId);

} Bene, la patch funziona, se chiudiamo un occhio sul fatto che winamp perde (temporaneamente) tutta la configurazione :) Infatti lanciando la nostra phase3 partirà con la skin di default e ci farà strane richieste di invio di feedback.

Api Hijacking

~api hijacking, #4

Api hijacking, dirottare le api? Chevvordì? Semplicemente intercettare le chiamate alle api ponendoci nel mezzo, come un layer tra il target e il sistema, con tutta la libertà di agire sui parametri da passare ultimamente alla vera api, neutralizzare la chiamata, o eseguire del nostro codice al posto di quello della api. E a che serve? Mettiamo il caso che il target chiami GetLocalTime per sapere che giorno è e si basi su questa informazione per decidere se il trial è scaduto... Capito no? :)

In questo esempio scriviamo un logger: l'output del nostro programma conterrà tutte le chiamate a RegCreateKeyA, con tanto di parametri.

In che modo possiamo intervenire ogni volta che viene chiamata RegCreateKeyA? Ma con un breakpoint ovviamente :) È opportuno fare uno schemino per capire bene come funziona il giochetto:

1. Al system breakpoint leggiamo dalla IAT l'indirizzo al quale RegCreateKeyA è mappata nell'address space di winamp.
2. Sempre al system bp scriviamo un int 3 sul primo byte di RegCreateKeyA, e stiamo ad aspettare che scatti il breakpoint...

3. Quando scatta il bp su RegCreateKeyA scriviamo il byte originale al posto dell'int 3 e risistemiamo eip,
4. poi settiamo la trap flag che scatterà alla seconda istruzione di RegCreatekeyA;
5. ora leggiamo e stampiamo a schermo i parametri della funzione;
→ qui volendo potremmo modificare a nostro piacimento i parametri ;)
6. infine aspettiamo che scatti la trap (punto 7).

7. Quando scatta la trap riscriviamo l'int 3 alla prima istruzione di RegCreateKeyA,
8. poi rimuoviamo la trap flag,
9. e aspettiamo che scatti il breakpoint (punto 3)

Ecco la sintassi di RegCreateKey: LONG RegCreateKey(

 HKEY hKey,
 LPCTSTR lpSubKey,
 PHKEY phkResult

); hKey
[in] handle di una chiave aperta (un numero di identificazione) o una delle chiavi predefinite: HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE o HKEY_USERS.
lpSubKey
[in] stringa che contiene il nome di una sottochiave di hKey.
phkResult
[out] puntatore a una variabile che riceverà l'handle della chiave che stiamo aprendo.

Bene, traduciamo in c++ tutto quello che abbiamo detto :) // phase4.cpp

  1. include <windows.h>
  2. include <stdio.h>

char filename[] = "winamp.exe"; char remote[300]; BYTE bp = 0xCC; // int 3 BYTE ob; // il byte che rimpiazzeremo con l'int 3 BYTE chr;

void main() {

 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 ZeroMemory( &si, sizeof(si) );
 si.cb = sizeof(si);
 ZeroMemory( &pi, sizeof(pi) );
 CreateProcess(
   filename,
   NULL,NULL,NULL,
   false,
   DEBUG_PROCESS,
   NULL,NULL,
   &si,&pi);
 HANDLE hProc = pi.hProcess;
 HANDLE hMainT = pi.hThread;
 DEBUG_EVENT DebugEv;
 DWORD dwContinueStatus;
 int bpcounter = 0;
 int rc = 0;
 DWORD junk;
 DWORD regcreatekey = 0;
 DWORD code;
 void* addr;
 DWORD temp;
 CONTEXT tc;
 for(;;)
 {
   dwContinueStatus = DBG_CONTINUE;
   WaitForDebugEvent(&DebugEv, INFINITE);
   code = DebugEv.u.Exception.ExceptionRecord.ExceptionCode;
   addr = DebugEv.u.Exception.ExceptionRecord.ExceptionAddress;
   switch (DebugEv.dwDebugEventCode)
   {
     case EXCEPTION_DEBUG_EVENT:
     {
       if (code == EXCEPTION_BREAKPOINT)
       {
         if (bpcounter == 0) // system breakpoint
         {
           printf("system breakpoint hit (%u) at [%.8X]\n",bpcounter,addr);
           // leggiamo l'indirizzo di RegCreateKey
           ReadProcessMemory(hProc,(void*)0x453000,&regcreatekey,4,&junk);
           printf("RegCreateKeyA's address: 0x%.8X\n\n",regcreatekey);
           // salviamo il byte e settiamo il breakpoint su RegCreateKey
           ReadProcessMemory(hProc,(void*)regcreatekey,&ob,1,&junk);
           WriteProcessMemory(hProc,(void*)regcreatekey,&bp,1,&junk);
         }
         else if (addr == (void*)regcreatekey) // breakpoint su RegCreateKey
         {
           // riscriviamo il byte originale
           WriteProcessMemory(hProc,(void*)regcreatekey,&ob,1,&junk);
           // riallineiamo eip e attiviamo la trap flag
           tc.ContextFlags = CONTEXT_ALL;
           GetThreadContext(hMainT,&tc);
           tc.EFlags |= 0x100;
           tc.Eip--;
           printf("*** breakpoint on RegCreateKey, realigned and trap flag set\n");
           // leggiamo i parametri di RegCreateKey
           // esp+4 = hKey
           // esp+8 = lpSubKey
           // esp+C = phkResult
           // leggiamo hKey
           ReadProcessMemory(hProc,(void*)(tc.Esp+4),&temp,4,&junk);
           // se è un valore noto stampiamo il nome, altrimenti il numero
           switch (temp)
           {
             case HKEY_CLASSES_ROOT:
               printf("* hKey: HKEY_CLASSES_ROOT\n");
               break;
             case HKEY_CURRENT_CONFIG:
               printf("* hKey: HKEY_CURRENT_CONFIG\n");
               break;
             case HKEY_CURRENT_USER:
               printf("* hKey: HKEY_CURRENT_USER\n");
               break;
             case HKEY_LOCAL_MACHINE:
               printf("* hKey: HKEY_LOCAL_MACHINE\n");
               break;
             case HKEY_USERS:
               printf("* hKey: HKEY_USERS\n");
               break;
             default:
               printf("* hKey: %.8X\n",temp);
           }
           // leggiamo lpSubKey
           ReadProcessMemory(hProc,(void*)(tc.Esp+8),&temp,4,&junk);
           // printiamo l'indirizzo della stringa
           printf("* lpSubKey: %.8X -> ",temp);
           // leggiamo la stringa e stampiamola
           for (rc = 0; rc<300; rc++)
           {
              ReadProcessMemory(hProc,(void*)(temp+rc),&chr,1,&junk);
              if (chr == 0)
              {
                printf("\n");
                break;
              }
              printf("%c",chr);
           }
           // leggiamo phkResult e printiamolo
           ReadProcessMemory(hProc,(void*)(tc.Esp+12),&temp,4,&junk);
           printf("* phkResult: %.8X\n",temp);
           // settiamo le modifiche al context
           SetThreadContext(hMainT,&tc);
         }
         bpcounter++;
       }
       if (code == EXCEPTION_SINGLE_STEP) // trap flag
       {
         // ripiazziamo il breakpoint su RegCreateKey
         WriteProcessMemory(hProc,(void*)regcreatekey,&bp,1,&junk);
         // rimuoviamo la trap flag
         tc.ContextFlags = CONTEXT_ALL;
         GetThreadContext(hMainT,&tc);
         tc.EFlags &= 0xFFFFFEFF;
         SetThreadContext(hMainT,&tc);
         printf("*** trap, breakpoint set\n\n");
       }
     break;
     }
     case EXIT_PROCESS_DEBUG_EVENT:
     ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus);
     return;
     break;
   }
   ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus);
 }

} Vediamo i risultati: durante l'avvio di winamp RegCreateKey viene chiamata una sola volta. Ma se andiamo nelle "Preferences"(ctrl+P)→"General Preferences", clickiamo su "File Types" e poi su un'altra voce, vedremo molti accessi a HKEY_CLASSES_ROOT con cui winamp controlla le associazioni delle diverse estensioni.


Note Finali

Un grazie a faina (come non ci conosciamo?!? :) che ha scritto un gran tute sull'argomento che mi ha invogliato a completare il mio :)
E poi grazie Què che questa idea delle boxes per il codice è una gran trovata :) Certo il wiki è pure meglio :)
Ovviamente per chiarimenti, migliorie o correzioni mandatemi una mail.
Ci vediamo al prossimo essay... bye.


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.