0rp Virtual Machine Reversing
From UIC
0rp Impossible Crackme #2 Reversing
Contents |
| Infos | |
|---|---|
| Author: | Pn |
| Email: | |
| Website: | no site |
| Date: | 24/04/2009 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Si apprende facendo e si capisce come fare le cose guardando altri farle |
Introduzione
Sulla Uic fino ad ora non c'era ancora alcun tutorial sul reversing di virtual machine, e quindi ho deciso di farne uno.
Il tutorial non spiega come crackare, ma spiega il funzionamento della virtual machine e come ci si deve muovere in un contesto del genere.
Tools
IDA 4.9 free
OllyDbg 2 beta
RDG o PEiD o ExplorerSuite
Crackme
Link e Riferimenti
Discussione del crackme su Woodmann
Essay
Disassembliamo il file con IDA 4.9, ed aggiungiamo le signature vc mfc, così da poter riconoscere il maggior numero di funzioni.
Il file come potete controllare con il Cff o con il PeiD o con RDG è stato compilato con il Visual Studio, quindi possiamo trovare il Main molto velocemente.
.text:00401000
.text:00401000 Text = byte ptr -404h
.text:00401000 var_4 = dword ptr -4
.text:00401000
.text:00401000 sub esp, 404h
.text:00401006 mov eax, dword_40C004
.text:0040100B xor eax, esp
.text:0040100D mov [esp+404h+var_4], eax
.text:00401014 push 1000h ; size_t
.text:00401019 push 0 ; int
.text:0040101B push offset unk_41C330 ; void *
.text:00401020 call _memset
.text:00401025 lea eax, [esp+410h+Text]
.text:00401029 push eax
.text:0040102A push 123h
.text:0040102F mov allocF, offset ?xm_allocate@@YGPAXK@Z ; xm_allocate(ulong)
.text:00401039 mov freeF, offset ?xm_free@@YGXPAX@Z ; xm_free(void *)
.text:00401043 mov sprintfF, offset _sprintf
.text:0040104D mov dword_40CF6C, offset unk_41C330
.text:00401057 mov dword_40CF70, offset sub_401100
.text:00401061 mov loadFunctionF, offset loc_401180
.text:0040106B call check
.text:00401070 add esp, 14h
.text:00401073 push 0 ; uType
.text:00401075 push offset Caption ; "mhmmhm"
.text:0040107A lea ecx, [esp+40Ch+Text]
.text:0040107E push ecx ; lpText
.text:0040107F push 0 ; hWnd
.text:00401081 call ds:MessageBoxA
.text:00401087 mov ecx, [esp+404h+var_4]
.text:0040108E xor ecx, esp
.text:00401090 xor eax, eax
.text:00401092 call sub_40119C
.text:00401097 add esp, 404h
.text:0040109D retn
.text:0040109D Main endp
0rp oltre all'eseguibile ha rilasciato anche i sorgenti del main e delle funzione protette dalla sua virtual machine, diamo un' occhiata:
{
ZeroMemory(globals, sizeof(globals));
*(DWORD *)(base + 0) = (DWORD)xm_allocate;
*(DWORD *)(base + 4) = (DWORD)xm_free;
*(DWORD *)(base + 8) = (DWORD)sprintf;
*(DWORD *)(base + 12) = (DWORD)globals;
*(DWORD *)(base + 16) = (DWORD)xm_printf;
*(DWORD *)(base + 20) = (DWORD)xm_export;
}
void main()
{
xm_init();
char result[1024];
check(0x123, result);
MessageBox(0, result, "mhmmhm", MB_OK);
}
void strcpy(data dest, data src)
{
for (int i = 0; src[i] != 0; i++)
dest[i] = src[i];
dest[i] = 0;
}
void __export check(int key, data result)
{
if (key == 42)
strcpy(result, "oh, youve keygenned me");
else
strcpy(result, "hmmh, no, try 42");
}
Chi ha un po' d' esperienza avrà sicuramente capito il disassemblato della Main, quindi andiamo a dare un occhiata alla funzione check
.text:004010A0 pusha
.text:004010A1 pushf
.text:004010A2 mov eax, offset allocF
.text:004010A7 add eax, 6FBFh
.text:004010AC jmp eax ; 413F1F
.text:004010AC check endp
Questo disasm non assomiglia minimamente a quello che avremmo aspettato di trovarci.
Questo pezzo di codice è il bridge tra il programma e la virtual machine.
.data:00413F1F call $+5
.data:00413F24 pop esi ; in esi c'è EIP
.data:00413F25 sub esi, 6FC4h ; Esi = Vm base offset (40cf60)
.data:00413F2B push 19E10h
.data:00413F30 call dword ptr [esi] ; xm_allocate
.data:00413F32 mov ebx, eax
.data:00413F34 mov [ebx+14h], esi ;ebx+14 = VmBase
.data:00413F37 lea eax, [ebx+100h]
.data:00413F3D mov [ebx+1Ch], eax ; ebx+1c = VmBase + 100
.data:00413F40 mov [ebx+0Ch], esp ; ebx+0c = VmBase + 100
.data:00413F43 lea eax, [ebx+101D0h]
.data:00413F49 mov [ebx], eax ;ebx = VmBase + 101D0
.data:00413F4B mov [ebx+4], eax ;ebx+4 = VmBase + 101D0
.data:00413F4E mov dword ptr [ebx+24h], 7053h ; ebx+24 = Vm Instruction Offset
.data:00413F55 mov dword ptr [ebx+28h], 7F6F74BEh ;ebx+28 = Decode Word
Possiamo identificare ebx come il puntatore ad una struttura di questo tipo (più o meno) :
freeSpace1 dd ?
freeSpace2 dd ?
field_8 dd ?
freeSpace3 dd ?
field_10 dd ?
base dd ?
Field_18 dd ?
freeSpace4 dd ?
field_20 dd ?
instructionOffset dd ?
decodeWord dd ?
VmStruct ends
e quindi il disasm del resto di questa funzione diviene
.data:00413F5F add ebp, [ebx+VmStruct.base]
.data:00413F62 lea esi, [ebp+0]
.data:00413F65 mov eax, [esi]
.data:00413F67 mov ecx, 8
.data:00413F6C
.data:00413F6C loc_413F6C: ; CODE XREF: vmEntry+58#j
.data:00413F6C mov edx, [esi+ecx*4]
.data:00413F6F xor edx, [ebx+VmStruct.decodeWord]
.data:00413F72 add edx, [ebx+VmStruct.base]
.data:00413F75 xor eax, [edx]
.data:00413F77 loop loc_413F6C ; questo loop serve a calcorare la prossima istruzione
.data:00413F79 mov [ebx+VmStruct.instructionOffset], eax
.data:00413F7C lea esi, [ebp+48h]
.data:00413F7F mov eax, [esi]
.data:00413F81 mov ecx, 8
.data:00413F86
.data:00413F86 loc_413F86: ; CODE XREF: vmEntry+72#j
.data:00413F86 mov edx, [esi+ecx*4]
.data:00413F89 xor edx, [ebx+VmStruct.decodeWord]
.data:00413F8C add edx, [ebx+VmStruct.base]
.data:00413F8F xor eax, [edx]
.data:00413F91 loop loc_413F86 ; questo loop serve a calcolare la prossima parola di decodifica
.data:00413F93 push eax ;pusha la prossima decodeWord
.data:00413F94 lea esi, [ebp+24h]
.data:00413F97 mov eax, [esi]
.data:00413F99 mov ecx, 8
.data:00413F9E
.data:00413F9E loc_413F9E: ; CODE XREF: vmEntry+8A#j
.data:00413F9E mov edx, [esi+ecx*4]
.data:00413FA1 xor edx, [ebx+VmStruct.decodeWord]
.data:00413FA4 add edx, [ebx+VmStruct.base]
.data:00413FA7 xor eax, [edx]
.data:00413FA9 loop loc_413F9E ; questo loop calcola la prossima funzione (offset) della virtual machine con cui decodificare la vmInstruction
.data:00413FAB pop [ebx+VmStruct.decodeWord] ; salva il valore pushato precedentemente
.data:00413FAE add eax, [ebx+VmStruct.base]
.data:00413FB1 jmp eax ;salta alla funzione di decodifica della vmInstruction
.data:00413FB1 vmEntry endp
A questo punto tengo a precisare che i loop nelle varie funzioni di decodifica delle vmInstruction sono sempre gli stessi, per riconoscerli basta andare a vedere la struttura (che chiameremo vmInstruction) puntata da ebp, che ricostruiremo più avanti.
.data:0040D0EE mov ebp, [ebx+VmStruct.instructionOffset]
.data:0040D0F1 add ebp, [ebx+VmStruct.base]
.data:0040D0F4 lea esi, [ebp+6Ch]
.data:0040D0F7 mov eax, [esi]
.data:0040D0F9 mov ecx, 8
.data:0040D0FE
.data:0040D0FE loc_40D0FE: ; CODE XREF: function1_+1B#j
.data:0040D0FE mov edx, [esi+ecx*4]
.data:0040D101 xor edx, [ebx+VmStruct.decodeWord]
.data:0040D104 add edx, [ebx+VmStruct.base]
.data:0040D107 xor eax, [edx]
.data:0040D109 loop loc_40D0FE
.data:0040D10B mov [ebx+4Ch], eax ; eax = offset
.data:0040D10E lea esi, [ebp+90h]
.data:0040D114 mov eax, [esi]
.data:0040D116 mov ecx, 8
.data:0040D11B
.data:0040D11B loc_40D11B: ; CODE XREF: function1_+38#j
.data:0040D11B mov edx, [esi+ecx*4]
.data:0040D11E xor edx, [ebx+VmStruct.decodeWord]
.data:0040D121 add edx, [ebx+VmStruct.base]
.data:0040D124 xor eax, [edx]
.data:0040D126 loop loc_40D11B
.data:0040D128 mov [ebx+50h], eax ; eax = value
;istruzione da eseguire
.data:0040D12B mov eax, [ebx+4Ch]
.data:0040D12E mov ecx, [ebx+50h]
.data:0040D131 mov [ebx+eax], ecx ; mov VmReg, value
.data:0040D134 lea esi, [ebp+0]
.data:0040D137 mov eax, [esi]
.data:0040D139 mov ecx, 8
.data:0040D13E
.data:0040D13E loc_40D13E: ; CODE XREF: function1_+5B#j
.data:0040D13E mov edx, [esi+ecx*4]
.data:0040D141 xor edx, [ebx+VmStruct.decodeWord]
.data:0040D144 add edx, [ebx+VmStruct.base]
.data:0040D147 xor eax, [edx]
.data:0040D149 loop loc_40D13E
.data:0040D14B mov [ebx+VmStruct.instructionOffset], eax
.data:0040D14E lea esi, [ebp+48h]
.data:0040D151 mov eax, [esi]
.data:0040D153 mov ecx, 8
.data:0040D158
.data:0040D158 loc_40D158: ; CODE XREF: function1_+75#j
.data:0040D158 mov edx, [esi+ecx*4]
.data:0040D15B xor edx, [ebx+VmStruct.decodeWord]
.data:0040D15E add edx, [ebx+VmStruct.base]
.data:0040D161 xor eax, [edx]
.data:0040D163 loop loc_40D158
.data:0040D165 push eax
.data:0040D166 lea esi, [ebp+24h]
.data:0040D169 mov eax, [esi]
.data:0040D16B mov ecx, 8
.data:0040D170
.data:0040D170 loc_40D170: ; CODE XREF: function1_+8D#j
.data:0040D170 mov edx, [esi+ecx*4]
.data:0040D173 xor edx, [ebx+VmStruct.decodeWord]
.data:0040D176 add edx, [ebx+VmStruct.base]
.data:0040D179 xor eax, [edx]
.data:0040D17B loop loc_40D170
.data:0040D17D pop [ebx+VmStruct.decodeWord]
.data:0040D180 add eax, [ebx+VmStruct.base]
.data:0040D183 jmp eax
.data:0040D183 function1_ endp
Come potete notare ho già fatto un'analisi del disasm (effettuata anche con l'aiuto del debugger OllyDbg 2 beta) e da questa mi sono ricavato la seguente struttura:
00000000 nextInstruction dd ?
00000004 db ? ; undefined
...
00000023 db ? ; undefined
00000024 nextVmFunction dd ?
00000028 db ? ; undefined
...
00000047 db ? ; undefined
00000048 nextDecodeWord dd ?
0000004C db ? ; undefined
...
0000006B db ? ; undefined
0000006C offset_reg dd ? ; il valore calcolato può essere o un offset o usato per indicare il registro della vm da usare
00000070 db ? ; undefined
...
0000008F db ? ; undefined
00000090 value_reg db ? ; il valore calcolato può essere o un immediato (numero) o usato per indicare il registro della vm da usare
VmInstruction ends
Steppando con un debugger, tra le varie funzioni ci si rende conto che tutte le funzioni della virtual machine iniziano con
add ebp, [ebx+VmStruct.base]
sarebbe a dire: 8B 6B 24 03 6B 14, quindi con IDA effettuiamo una ricerca di questi byte così da trovare tutte le funzioni della Virtual Machine (18 + VmEntry).
C'è anche un trick antidebug, più precisamente di un trick antibp.
Nei vari loop vengono presi dei valori da vari indirizzi di memoria, e spesso e volentieri alcuni indirizzi fanno parte dell'intervallo delle funzioni della virtual machine; in questo modo, se vengono messi dei bp (byte 0xCC) in queste funzioni per breakare, i conti risulteranno di certo errati e di conseguenza ci saranno degli access violation.
Ecco a voi l'analisi di quella che ho chiamato function2_, dove c'è una ricostruzione quasi completa delle strutture usate
.data:0040D85B mov ebp, [ebx+VmStruct.instructionOffset]
.data:0040D85E add ebp, [ebx+VmStruct.base]
.data:0040D861 lea esi, [ebp+VmInstruction.offset_reg]
.data:0040D864 mov eax, [esi]
.data:0040D866 mov ecx, 8
.data:0040D86B
.data:0040D86B loc_40D86B: ; CODE XREF: function2_+1B#j
.data:0040D86B mov edx, [esi+ecx*4]
.data:0040D86E xor edx, [ebx+VmStruct.decodeWord]
.data:0040D871 add edx, [ebx+VmStruct.base]
.data:0040D874 xor eax, [edx]
.data:0040D876 loop loc_40D86B ; viene calcolato quale registro della vm usare
.data:0040D878 mov [ebx+4Ch], eax ; ebx+4c si può considerare un registro volatile della vm
.data:0040D87B lea esi, [ebp+VmInstruction.value_reg]
.data:0040D881 mov eax, [esi]
.data:0040D883 mov ecx, 8
.data:0040D888
.data:0040D888 loc_40D888: ; CODE XREF: function2_+38#j
.data:0040D888 mov edx, [esi+ecx*4]
.data:0040D88B xor edx, [ebx+VmStruct.decodeWord]
.data:0040D88E add edx, [ebx+VmStruct.base]
.data:0040D891 xor eax, [edx]
.data:0040D893 loop loc_40D888 ; viene calcolato quale registro della vm usare
.data:0040D895 mov [ebx+50h], eax ;ebx+50 è un altro registro volatile della vm
.data:0040D898 mov eax, [ebx+50h]
.data:0040D89B mov eax, [ebx+eax] ; prende (in questo caso) un offset da un registro della vm
.data:0040D89E mov ecx, [eax] ; ne prende il valore
.data:0040D8A0 mov eax, [ebx+4Ch]
.data:0040D8A3 mov [ebx+eax], ecx ; mov VmReg, Mem/Stack Value
.data:0040D8A6 lea esi, [ebp+VmInstruction.nextInstruction]
.data:0040D8A9 mov eax, [esi]
.data:0040D8AB mov ecx, 8
.data:0040D8B0
.data:0040D8B0 loc_40D8B0: ; CODE XREF: function2_+60#j
.data:0040D8B0 mov edx, [esi+ecx*4]
.data:0040D8B3 xor edx, [ebx+VmStruct.decodeWord]
.data:0040D8B6 add edx, [ebx+VmStruct.base]
.data:0040D8B9 xor eax, [edx]
.data:0040D8BB loop loc_40D8B0
.data:0040D8BD mov [ebx+VmStruct.instructionOffset], eax
.data:0040D8C0 lea esi, [ebp+VmInstruction.nextDecodeWord]
.data:0040D8C3 mov eax, [esi]
.data:0040D8C5 mov ecx, 8
.data:0040D8CA
.data:0040D8CA loc_40D8CA: ; CODE XREF: function2_+7A#j
.data:0040D8CA mov edx, [esi+ecx*4]
.data:0040D8CD xor edx, [ebx+VmStruct.decodeWord]
.data:0040D8D0 add edx, [ebx+VmStruct.base]
.data:0040D8D3 xor eax, [edx]
.data:0040D8D5 loop loc_40D8CA
.data:0040D8D7 push eax
.data:0040D8D8 lea esi, [ebp+VmInstruction.nextVmFunction]
.data:0040D8DB mov eax, [esi]
.data:0040D8DD mov ecx, 8
.data:0040D8E2
.data:0040D8E2 loc_40D8E2: ; CODE XREF: function2_+92#j
.data:0040D8E2 mov edx, [esi+ecx*4]
.data:0040D8E5 xor edx, [ebx+VmStruct.decodeWord]
.data:0040D8E8 add edx, [ebx+VmStruct.base]
.data:0040D8EB xor eax, [edx]
.data:0040D8ED loop loc_40D8E2
.data:0040D8EF pop [ebx+VmStruct.decodeWord]
.data:0040D8F2 add eax, [ebx+VmStruct.base]
.data:0040D8F5 jmp eax
.data:0040D8F5 function2_ endp
Andando all'indirizzo 0040F58E, possiamo notare che dopo i consueti primi due loop, c'è un cmp+jmp e quindi il flusso del programma potrebbe seguire due differenti percorsi, in uno dei quali vengono usati altri membri della struttura VmInstruction, la quale deve essere modificata in questo modo:
00000000 nextInstruction dd ?
00000004 db ? ; undefined
...
00000023 db ? ; undefined
00000024 nextVmFunction dd ?
00000028 db ? ; undefined
...
00000047 db ? ; undefined
00000048 nextDecodeWord dd ?
0000004C db ? ; undefined
...
0000006B db ? ; undefined
0000006C offset_reg dd ? ; il valore calcolato può essere o un offset o usato per indicare il registro della vm da usare
00000070 db ? ; undefined
...
0000008F db ? ; undefined
00000090 value_reg db ? ; il valore calcolato può essere o un immediato (numero) o usato per indicare il registro della vm da usare
000000B3 db ? ; undefined
000000B4 nextVmFunction2 dd ?
000000B8 db ? ; undefined
...
000000D7 db ? ; undefined
000000D8 nextDecodeWord2 dd ?
VmInstruction ends
ed ecco a voi il mio disasm con l'analisi di questa funzione:
.data:0040F58E mov ebp, [ebx+VmStruct.instructionOffset]
.data:0040F591 add ebp, [ebx+VmStruct.base]
.data:0040F594 lea esi, [ebp+VmInstruction.offset_reg]
.data:0040F597 mov eax, [esi]
.data:0040F599 mov ecx, 8
.data:0040F59E
.data:0040F59E loc_40F59E: ; CODE XREF: function3+1B#j
.data:0040F59E mov edx, [esi+ecx*4]
.data:0040F5A1 xor edx, [ebx+VmStruct.decodeWord]
.data:0040F5A4 add edx, [ebx+VmStruct.base]
.data:0040F5A7 xor eax, [edx]
.data:0040F5A9 loop loc_40F59E
.data:0040F5AB cmp dword ptr [ebx+eax], 0 ; routine per i flag: cmp
.data:0040F5B2 jz short loc_40F602
.data:0040F5B4 lea esi, [ebp+VmInstruction]
.data:0040F5B7 mov eax, [esi]
.data:0040F5B9 mov ecx, 8
.data:0040F5BE
.data:0040F5BE loc_40F5BE: ; CODE XREF: function3+3B#j
.data:0040F5BE mov edx, [esi+ecx*4]
.data:0040F5C1 xor edx, [ebx+VmStruct.decodeWord]
.data:0040F5C4 add edx, [ebx+VmStruct.base]
.data:0040F5C7 xor eax, [edx]
.data:0040F5C9 loop loc_40F5BE
.data:0040F5CB mov [ebx+VmStruct.instructionOffset], eax
.data:0040F5CE lea esi, [ebp+VmInstruction.nextDecodeWord]
.data:0040F5D1 mov eax, [esi]
.data:0040F5D3 mov ecx, 8
.data:0040F5D8
.data:0040F5D8 loc_40F5D8: ; CODE XREF: function3+55#j
.data:0040F5D8 mov edx, [esi+ecx*4]
.data:0040F5DB xor edx, [ebx+VmStruct.decodeWord]
.data:0040F5DE add edx, [ebx+VmStruct.base]
.data:0040F5E1 xor eax, [edx]
.data:0040F5E3 loop loc_40F5D8
.data:0040F5E5 push eax
.data:0040F5E6 lea esi, [ebp+VmInstruction.nextVmFunction]
.data:0040F5E9 mov eax, [esi]
.data:0040F5EB mov ecx, 8
.data:0040F5F0
.data:0040F5F0 loc_40F5F0: ; CODE XREF: function3+6D#j
.data:0040F5F0 mov edx, [esi+ecx*4]
.data:0040F5F3 xor edx, [ebx+VmStruct.decodeWord]
.data:0040F5F6 add edx, [ebx+VmStruct.base]
.data:0040F5F9 xor eax, [edx]
.data:0040F5FB loop loc_40F5F0
.data:0040F5FD jmp loc_40F654
.data:0040F602 ; ---------------------------------------------------------------------------
.data:0040F602
.data:0040F602 loc_40F602: ; CODE XREF: function3+24#j
.data:0040F602 lea esi, [ebp+VmInstruction.value_reg]
.data:0040F608 mov eax, [esi]
.data:0040F60A mov ecx, 8
.data:0040F60F
.data:0040F60F loc_40F60F: ; CODE XREF: function3+8C#j
.data:0040F60F mov edx, [esi+ecx*4]
.data:0040F612 xor edx, [ebx+VmStruct.decodeWord]
.data:0040F615 add edx, [ebx+VmStruct.base]
.data:0040F618 xor eax, [edx]
.data:0040F61A loop loc_40F60F
.data:0040F61C mov [ebx+VmStruct.instructionOffset], eax
.data:0040F61F lea esi, [ebp+VmInstruction.nextDecodeWord2]
.data:0040F625 mov eax, [esi]
.data:0040F627 mov ecx, 8
.data:0040F62C
.data:0040F62C loc_40F62C: ; CODE XREF: function3+A9#j
.data:0040F62C mov edx, [esi+ecx*4]
.data:0040F62F xor edx, [ebx+VmStruct.decodeWord]
.data:0040F632 add edx, [ebx+VmStruct.base]
.data:0040F635 xor eax, [edx]
.data:0040F637 loop loc_40F62C
.data:0040F639 push eax
.data:0040F63A lea esi, [ebp+VmInstruction.nextVmFunction2]
.data:0040F640 mov eax, [esi]
.data:0040F642 mov ecx, 8
.data:0040F647
.data:0040F647 loc_40F647: ; CODE XREF: function3+C4#j
.data:0040F647 mov edx, [esi+ecx*4]
.data:0040F64A xor edx, [ebx+VmStruct.decodeWord]
.data:0040F64D add edx, [ebx+VmStruct.base]
.data:0040F650 xor eax, [edx]
.data:0040F652 loop loc_40F647
.data:0040F654
.data:0040F654 loc_40F654: ; CODE XREF: function3+6F#j
.data:0040F654 pop [ebx+VmStruct.decodeWord]
.data:0040F657 add eax, [ebx+VmStruct.base]
.data:0040F65A jmp eax
.data:0040F65A function3 endp
A questo punto l'analisi si può tranquillamente fare su tutte le restanti funzioni della virtual machine.
Se volete sapere come si cracka il target preso in esame, vi rimando al post di ZaiRoN su woodmann.
Se invece volete ricostruire le istruzioni della virtual machine, vi conviene usare IDApython o idc su IDA o farvi un programma ad hoc.
Conclusione
Ringrazio tutti.
Pn =)
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 malevoli 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.