Zoom Icon

0rp Virtual Machine Reversing

From UIC

0rp Impossible Crackme #2 Reversing

Contents


Infos
Author: Pn
Email: Email
Website: no site
Date: 24/04/2009 (dd/mm/yyyy)
Level: Some skills are required
Language: Italian Image:Flag_Italian.gif
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 Main            proc near               ; CODE XREF: start-5C#p
.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:

void xm_init()
{
        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 check           proc near               ; CODE XREF: Main+6B#p
.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 vmEntry         proc near
.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) :

VmStruct        struc ; (sizeof=0x2C)
  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:00413F5C                 mov     ebp, [ebx+VmStruct.instructionOffset]
.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 function1_      proc near
.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:

VmInstruction   struc
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

mov     ebp, [ebx+VmStruct.instructionOffset]
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 function2_      proc near
.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:

VmInstruction   struc
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 function3       proc near
.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.