Zoom Icon

Win64 BeaBA crackme

From UIC

BeatriX's BeaBA solution

Contents


Infos
Author: Pnluck
Email: Email
Website: http:\\pnluck.netsons.org
Date: 22/07/2008 (dd/mm/yyyy)
Level: Slightly hard
Language: Italian Image:Flag_Italian.gif
Comments: Si apprende facendo e si capisce come fare le cose guardando altri farle (Noam Chomsky)



Introduzione

Questo crackme ha dei bei trick per x64: come cambiare il membro UnwindInfoAddress della struttura IMAGE_RUNTIME_FUNCTION_ENTRY (quella usata dall'Exception Directory, vedi i link sotto) ed un pò di code obfuscation.


Tools

IDA 5.2
WinDBG 64-bit Version


Link e Riferimenti

Improving Automated Analysis of Windows x64 Binaries: è consigliata la lettura
X64_Assembly
BeaBa crackme


Essay

Iniziamo col disassemblare il crackme in IDA.

.text:00000000004036F9                 nop     dword ptr [rax]
.text:00000000004036FC                 mov     rax, 0
.text:0000000000403703                 nop     dword ptr [rax]
.text:0000000000403706                 mov     rax, [rax]     ; viene generata un eccezione
.text:0000000000403709 loc_403709:                             ; DATA XREF: .data:0000000000416114�o
.text:0000000000403709                                         ; .pdata:ExceptionDir�o

All'indirizzo 403706, come potete notare, viene generata un'eccezione di access violation. Per sapere quale funzione gestisce l'eccezione, dobbiamo vedere la RUNTIME_FUNCTION relativa a questa funzione.
Nel WinDBG basta digitare ".fnent.fnent significa function entry rip" o ".fnent 403706" per avere tutte le info:

0:000> .fnent rip
Debugger function entry 00000000`01c0f9f0 for:

BeginAddress = 00000000`00001000
EndAddress = 00000000`00003709
UnwindInfoAddress = 00000000`0000ae90

Unwind info at 00000000`0040ae90, c bytes
version 1, flags 3, prolog 0, codes 0
frame reg 0, frame offs 0
handler routine: image00000000_00400000+0x1523 (00000000`00401523), data 0

Oppure in IDA cliccate su .pdata:ExceptionDir, a questo punto avrete avanti ciò:

.pdata:0000000000417000 ExceptionDir    RUNTIME_FUNCTION <rva sub_401000, rva loc_403709, rva stru_40AE90>

Andate all'indirizzo indicato del terzo membro, che sarebbe l'indirizzo che ha la struttura UNWIND_INFO

.rdata:000000000040AE90 stru_40AE90     UNWIND_INFO <19h, 0, 0, 0>
.rdata:000000000040AE90                                         ; DATA XREF: .pdata:ExceptionDir�o
.rdata:000000000040AE94                 dd rva loc_401523

rva loc_401523 ci dice proprio quale è rva della funzione che si occupa di gestire l'eccezione.
Andando a quell'indirizzo noterete un bel pò di codice offuscato, la struttra del codice è pressappoco così

addr0: jmp addr1;

;...junk code...

addr1: call addr2:

db xx

addr2: call addr3

db xx
addr3:
add     dword ptr [rsp+8], 12h
add     dword ptr [rsp], 0Ah
retn

db xx

addr4:
;...codice inutile...
js      addr5
jns     addr5

add5: ;vengono ripetute un paio di volte il codice che va da addr0 ad add5

addr6:  
rdtsc
mov     ecx, eax
rdtsc
sub     ecx, eax
not     ecx
cmp     ecx, 10000h
no_jmp:
jg      no_jmp
push    584Eh
js      addr7
jns     addr7

...

Tutto questo viene ripetuto ancora un paio di volte, finchè son si arriva ad un pezzo di codice davvero interessante:

.text:000000000040169A                 push    rsp
.text:000000000040169B                 and     spl, 0F0h
.text:000000000040169F                 xor     rcx, rcx
.text:00000000004016A2                 sub     rsp, 20h
.text:00000000004016A6                 nop     dword ptr [rax]
.text:00000000004016A9                 call    _GetModuleHandle
.text:00000000004016AE                 add     rsp, 20h
.text:00000000004016B2                 pop     rsp
.text:00000000004016B3                 mov     cs:ImgBase, rax
.text:00000000004016BA                 call    Get_EH_table
.text:00000000004016BF                 mov     rsi, cs:_handle_routine_va
.text:00000000004016C6                 mov     rax, 401000h ;è l'indirizzo della nuova funzione che deve gestire l'eccezione
.text:00000000004016D0                 sub     rax, cs:ImgBase;  mi ricavo il suo rva
.text:00000000004016D7                 mov     [rsi], eax; e lo sostituisco a .rdata:000000000040AE94
.text:00000000004016D9                 xor     eax, eax
.text:00000000004016DB                 div     eax ;genero un'altra eccezione
.text:00000000004016DD                 retn

Dopo l'eccezione, in 401000 ci ritroviamo di nuovo nel jungle code, dopo un pò di pazienza nell'analisi con ida, troviamo un'altro pezzo di codice, simile a quello precedente

.text:000000000040135B loc_40135B:                             ; CODE XREF: .text:00000000004012EC�j
.text:000000000040135B                                         ; .text:00000000004012F2�j
.text:000000000040135B                 mov     rsi, cs:_handle_routine_va
.text:0000000000401362                 mov     rax, 401721h ;nuova funzione che deve gestire l'eccezione
.text:000000000040136C                 sub     rax, cs:ImgBase
.text:0000000000401373                 mov     [rsi], eax
.text:0000000000401375                 jmp     loc_4014E4

Infatti l'eccezione sarà generata da questi byte

.text:0000000000401520 unk_401520      db  82h ; é             ; CODE XREF: .text:00000000004014B1�j
.text:0000000000401520                                         ; .text:00000000004014B7�j
.text:0000000000401521                 db  36h ; 6
.text:0000000000401522                 db  10h

Quindi andiamo ad analizzare il codice all'indirizzo 401721:

.text:0000000000401721                 mov     rsp, [r8+98h]
.text:0000000000401728                 mov     rsi, cs:_handle_routine_va
.text:000000000040172F                 mov     rax, 403346h
.text:0000000000401739                 sub     rax, cs:ImgBase
.text:0000000000401740                 mov     [rsi], eax
.text:0000000000401742                 jmp     loc_4017EC

Ok non andiamo a 403346, stavolta continuiamo ad analizza il flusso del programma, dopo un pò di analisi arriveremo a questo pezzo di codice:

.text:00000000004018A7 loc_4018A7:                             ; CODE XREF: .text:loc_40187E�j
.text:00000000004018A7                                         ; .text:0000000000401885�j
.text:00000000004018A7                 push    rsp
.text:00000000004018A8                 and     spl, 0F0h
.text:00000000004018AC                 nop     dword ptr [rax]
.text:00000000004018AF                 push    0
.text:00000000004018B1                 push    80h
.text:00000000004018B6                 push    3
.text:00000000004018B8                 mov     r9, 0
.text:00000000004018BF                 mov     r8, 0
.text:00000000004018C6                 mov     rdx, 0FFFFFFFF80000000h
.text:00000000004018CD                 mov     rcx, 416023h ; "Warning"
.text:00000000004018D7                 sub     rsp, 20h
.text:00000000004018DB                 nop     dword ptr [rax]
.text:00000000004018DE                 mov     rax, 401AA1h    ; return address
.text:00000000004018E8                 push    rax
.text:00000000004018E9                 nop     dword ptr [rax]
.text:00000000004018EC                 jmp     CreateFileA

Questo codice non fa altro che tentare di aprire il file warning, faccio notare una cosa: dopo il jmp a CreateFile l'indirizzo di ritorno è 401aa1:

.text:0000000000401A9C loc_401A9C:                             ; CODE XREF: .text:0000000000401A2D�j
.text:0000000000401A9C                                         ; .text:0000000000401A33�j
.text:0000000000401A9C                 call    CreateFileA
.text:0000000000401AA1                 add     rsp, 38h
.text:0000000000401AA5                 pop     rsp
.text:0000000000401AA6                 cmp     rax, 0FFFFFFFFFFFFFFFFh
.text:0000000000401AAA                 jnz     short loc_401AB2
.text:0000000000401AAC                 xor     rax, rax
.text:0000000000401AAF                 div     rax ;genera un'eccezione se il file non è stato aperto
.text:0000000000401AB2
.text:0000000000401AB2 loc_401AB2:                             ; CODE XREF: .text:0000000000401AAA�j
.text:0000000000401AB2                 mov     cs:file_handle, rax
.text:0000000000401AB9                 push    rsp
.text:0000000000401ABA                 and     spl, 0F0h
.text:0000000000401ABE                 push    0
.text:0000000000401AC0                 push    80h
.text:0000000000401AC5                 push    3
.text:0000000000401AC7                 mov     r9, 0
.text:0000000000401ACE                 mov     r8, 0
.text:0000000000401AD5                 mov     rdx, 0FFFFFFFF80000000h
.text:0000000000401ADC                 mov     rcx, 416000h ; "Register a name and a valid serial"
.text:0000000000401AE6                 sub     rsp, 20h
.text:0000000000401AEA                 nop     dword ptr [rax]
.text:0000000000401AED                 mov     rax, 401C9Ah    ; return address
.text:0000000000401AF7                 push    rax
.text:0000000000401AF8                 nop     dword ptr [rax]
.text:0000000000401AFB                 jmp     CreateFileA
;....
.text:0000000000401C95                 call    CreateFileA
.text:0000000000401C9A                 add     rsp, 38h
.text:0000000000401C9E                 pop     rsp
.text:0000000000401C9F                 cmp     rax, 0FFFFFFFFFFFFFFFFh
.text:0000000000401CA3                 jnz     short loc_401CAB
.text:0000000000401CA5                 xor     rax, rax
.text:0000000000401CA8                 div     rax ;genera un'eccezione se il file non è stato aperto
.text:0000000000401CAB
.text:0000000000401CAB loc_401CAB:                             ; CODE XREF: .text:0000000000401CA3�j
.text:0000000000401CAB                 mov     cs:file_handle2, rax
.text:0000000000401CB2                 push    rsp
.text:0000000000401CB3                 and     spl, 0F0h
.text:0000000000401CB7                 mov     rdx, 0
.text:0000000000401CBE                 mov     rcx, cs:file_handle
.text:0000000000401CC5                 sub     rsp, 20h
.text:0000000000401CC9                 nop     dword ptr [rax]
.text:0000000000401CCC                 mov     rax, 401E97h    ; ret address
.text:0000000000401CD6                 push    rax
.text:0000000000401CD7                 nop     dword ptr [rax]
.text:0000000000401CDA                 jmp     GetFileSize
;...
.text:0000000000401E97 read_file1:
.text:0000000000401E97                 add     rsp, 20h
.text:0000000000401E9B                 pop     rsp
.text:0000000000401E9C                 cmp     rax, 1  ; verifica che la lunghezza del file
.text:0000000000401EA0                 jl      end_proc ; sia compresa tra 1 e 0x1e
.text:0000000000401EA6                 cmp     rax, 1Eh
.text:0000000000401EAA                 jg      end_proc
.text:0000000000401EB0                 mov     rdi, 4160C1h ; buffer del primo file
.text:0000000000401EBA                 push    rsp
.text:0000000000401EBB                 and     spl, 0F0h
.text:0000000000401EBF                 push    0
.text:0000000000401EC1                 mov     r9, 4160B9h
.text:0000000000401ECB                 mov     r8, rax
.text:0000000000401ECE                 mov     rdx, rdi
.text:0000000000401ED1                 mov     rcx, cs:file_handle
.text:0000000000401ED8                 sub     rsp, 20h
.text:0000000000401EDC                 nop     dword ptr [rax]
.text:0000000000401EDF                 call    ReadFile
.text:0000000000401EE4                 add     rsp, 28h
.text:0000000000401EE8                 pop     rsp
.text:0000000000401EE9                 jmp     loc_402070
;...junk code...
.text:0000000000402098 read_file2:                             ; CODE XREF: .text:0000000000401F49�j
.text:0000000000402098                                         ; .text:0000000000401F4F�j
.text:0000000000402098                 push    rsp
.text:0000000000402099                 and     spl, 0F0h
.text:000000000040209D                 mov     rdx, 0
.text:00000000004020A4                 mov     rcx, cs:file_handle2
.text:00000000004020AB                 sub     rsp, 20h
.text:00000000004020AF                 nop     dword ptr [rax]
.text:00000000004020B2                 call    GetFileSize
.text:00000000004020B7                 add     rsp, 20h
.text:00000000004020BB                 pop     rsp
.text:00000000004020BC                 cmp     rax, 0Fh ;verifica che la lunghezza del secondo file
.text:00000000004020C0                 jle     end_proc ; non sia minore o uguale a 0xF
.text:00000000004020C6                 mov     rax, 4160F8h ; buffer del secondo file
.text:00000000004020D0                 push    rsp
.text:00000000004020D1                 and     spl, 0F0h
.text:00000000004020D5                 push    0
.text:00000000004020D7                 mov     r9, 4160B9h
.text:00000000004020E1                 mov     r8, 10h
.text:00000000004020E8                 mov     rdx, rax
.text:00000000004020EB                 mov     rcx, cs:file_handle2
.text:00000000004020F2                 sub     rsp, 20h
.text:00000000004020F6                 nop     dword ptr [rax]
.text:00000000004020F9                 call    ReadFile
.text:00000000004020FE                 add     rsp, 28h
.text:0000000000402102                 pop     rsp
.text:0000000000402103                 push    rsp
.text:0000000000402104                 and     spl, 0F0h
.text:0000000000402108                 mov     rcx, cs:file_handle
.text:000000000040210F                 sub     rsp, 10h
.text:0000000000402113                 nop     dword ptr [rax]
.text:0000000000402116                 call    CloseHandle
.text:000000000040211B                 add     rsp, 10h
.text:000000000040211F                 pop     rsp
.text:0000000000402120                 push    rsp
.text:0000000000402121                 and     spl, 0F0h
.text:0000000000402125                 mov     rcx, cs:file_handle2
.text:000000000040212C                 sub     rsp, 10h
.text:0000000000402130                 nop     dword ptr [rax]
.text:0000000000402133                 call    CloseHandle
.text:0000000000402138                 add     rsp, 10h
.text:000000000040213C                 pop     rsp
.text:000000000040213D                 jmp     loc_4022AC

Riassumento: tutto questo codice nn fa altro che tentare di aprire due file e ne controlla la lunghezza: se è tutto corretto continua l'esecuzione normalmente, altrimenti esce.
Per quanto riguarda cosa devono contenere i due file, ve lo spiegherò tra poco.
Dopo ancora altro junk code, ci ritroviamo d'avanti il codice che controlla il contenuto del primo file (warning)

.text:000000000040247D check_warning_len:                      
.text:000000000040247D                                        
.text:000000000040247D                 mov     rsi, 4160C1h ; prende l'addr del buffer del primo file
.text:0000000000402487
.text:0000000000402487 loc_402487:                            
.text:0000000000402487                 cmp     byte ptr [rsi], 0
.text:000000000040248A                 jz      short loc_40249D ;esci quando trovi '\0'
.text:000000000040248C                 cmp     byte ptr [rsi], 20h ; continua se il byte è maggiore dello spazio ' ' ...
.text:000000000040248F                 jge     short loc_402492
.text:000000000040248F ; ---------------------------------------------------------------------------
.text:0000000000402491                 db  60h ; `
.text:0000000000402492 ; ---------------------------------------------------------------------------
.text:0000000000402492
.text:0000000000402492 loc_402492:                          
.text:0000000000402492                 cmp     byte ptr [rsi], 7Ah ;  ... o è minore di 'z'
.text:0000000000402495                 jle     short loc_402498
.text:0000000000402495 ; ---------------------------------------------------------------------------
.text:0000000000402497                 db  60h ; `
.text:0000000000402498 ; ---------------------------------------------------------------------------
.text:0000000000402498
.text:0000000000402498 loc_402498:                            
.text:0000000000402498                 inc     rsi
.text:000000000040249B                 jmp     short loc_402487
.text:000000000040249D ; ---------------------------------------------------------------------------
.text:000000000040249D
.text:000000000040249D loc_40249D:                            
.text:000000000040249D                 sub     rsi, 4160C1h
.text:00000000004024A4                 cmp     rsi, 8 ; se lunghezza del file è maggiore o uguale ad 8
.text:00000000004024A8                 jge     short loc_4024C6 ; continua l'esecuzione
.text:00000000004024AA                 mov     rcx, rsi
.text:00000000004024AD                 add     rsi, 4160C1h
.text:00000000004024B4                 mov     rdi, 4160C1h
.text:00000000004024BE                 xchg    rdi, rsi
.text:00000000004024C1                 cld
.text:00000000004024C2                 rep movsb
.text:00000000004024C4                 jmp     short check_warning_len
.text:00000000004024C6 ; ---------------------------------------------------------------------------
.text:00000000004024C6
.text:00000000004024C6 loc_4024C6:                            
.text:00000000004024C6                 jmp     continua_esecuzione

Dopo il check, il programma si preoccupa di caricare i dati da entrambi i file, vediamo:

.text:0000000000402679 load_data:                              
.text:0000000000402679                                        
.text:0000000000402679                 mov     rdi, 4160F8h ; prende l'addr del buffer del secondo file
.text:0000000000402683                 nop     dword ptr [rax]
.text:0000000000402686                 movhps  xmm5, qword ptr [rdi+8] ; carica nella parte alta di xmm5 la terza e la quarta dword presente nel buffer
.text:000000000040268A                 nop     dword ptr [rax]
.text:000000000040268D                 movlps  xmm5, qword ptr [rdi]; carica nella parte bassa di xmm5 la prima e la seconda dword presente nel buffer
.text:0000000000402690                 cvtdq2ps xmm5, xmm5 ; convete le dword in single precision floating point (32 bit)
.text:0000000000402693                 nop     dword ptr [rax]
.text:0000000000402696                 mov     rsi, 416051h ; prende l'addr di un array di floating point
.text:00000000004026A0                 movups  xmm1, oword ptr [rsi] ;carica quattro dword
.text:00000000004026A3                 cvtdq2ps xmm1, xmm1 ; e le converte in floating point
.text:00000000004026A6                 movups  xmm2, oword ptr [rsi+10h] ;idem con xmm2, etc...
.text:00000000004026AA                 cvtdq2ps xmm2, xmm2
.text:00000000004026AD                 movups  xmm3, oword ptr [rsi+20h]
.text:00000000004026B1                 cvtdq2ps xmm3, xmm3
.text:00000000004026B4                 movups  xmm4, oword ptr [rsi+30h]
.text:00000000004026B8                 cvtdq2ps xmm4, xmm4
.text:00000000004026BB                 nop     dword ptr [rax]
.text:00000000004026BE                 mulps   xmm1, xmm5 ; moltiplica  xmm1 per xmm5, etc..
.text:00000000004026C1                 nop     dword ptr [rax]
.text:00000000004026C4                 mulps   xmm2, xmm5
.text:00000000004026C7                 nop     dword ptr [rax]
.text:00000000004026CA                 mulps   xmm3, xmm5
.text:00000000004026CD                 mulps   xmm4, xmm5
.text:00000000004026D0                 nop     dword ptr [rax]
.text:00000000004026D3                 mov     rsi, cs:exp_dir_UnwindInfoAndress ;si ricava l'addr del membro UnwindInfoAndress di IMAGE_RUNTIME_FUNCTION_ENTRY
.text:00000000004026DA                 nop     dword ptr [rax]
.text:00000000004026DD                 mov     rax, 416118h
.text:00000000004026E7                 sub     rax, cs:ImgBase
.text:00000000004026EE                 mov     [rsi], eax ; e ne modifica l'indirizzo
.text:00000000004026F0                 mov     rdi, 416118h
.text:00000000004026FA                 add     rdi, 4 ; ricava l'indirizzo che contiene la funzione che gestisce l'eccezione....
.text:00000000004026FE                 mov     rax, cs:ImgBase
.text:0000000000402705                 call    loc_4028C1
.text:000000000040270A                 jmp     loc_402879
;...
.text:00000000004028C1 loc_4028C1:                            
.text:00000000004028C1                 pop     r8      ;r8 = 40270a
.text:00000000004028C3                 sub     r8, rax        
.text:00000000004028C6                 mov     [rdi], r8d ;...e viene settato l'rva a 270a
.text:00000000004028C9                 mov     rax, 0BEA2004h
.text:00000000004028D0                 mov     rax, [rax] ; viene generata un'eccezione
.text:00000000004028D3                 nop     dword ptr [rax] ;che ritorna qua
.text:00000000004028D6                 mov     rsi, cs:exp_dir_UnwindInfoAndress
.text:00000000004028DD                 nop     dword ptr [rax]
.text:00000000004028E0                 mov     rax, 416110h
.text:00000000004028EA                 sub     rax, cs:ImgBase
.text:00000000004028F1                 mov     [rsi], eax ; viene cambiato di nuovo il valore di UnwindInfoAndress (la funzione che gestisce l'eccezione è 403709)
.text:00000000004028F3                 jmp     loc_40296B

Se analizziamo il flusso del primo gestore d'eccezione impostato nel codice precedente, arriveremo a questo punto:

.text:00000000004028B5                 add     qword ptr [r8+0F8h], 3 ;rip += 3
.text:00000000004028BD                 xor     rax, rax ;eccezione corretta
.text:00000000004028C0                 retn ;continua l'esecuzione da 00000000004028D3 (vedi codice sopra)

Quindi il secondo file "Register a name and a valid serial", deve contenere al suo interno quattro floating point single precision, che verrano caricati poi nel registro xmm5, mentre nei registri xmm1/4 verranno prima caricati i seguenti valori:

xmm1:
0x16 0x22 0x17 0xD
2.200000e+001: 3.400000e+001: 2.300000e+001: 1.300000e+001

xmm2:
0xC 0x13 0xD 0x7
1.200000e+001: 1.900000e+001: 1.300000e+001: 7.000000e+000

xmm3:
0x15 0x21 0x16 0xC
2.100000e+001: 3.300000e+001: 2.200000e+001: 1.200000e+001

xmm4:
0xB 0x11 0xB 0x6
1.100000e+001: 1.700000e+001: 1.100000e+001: 6.000000e+000

che verranno moltiplicati con i quattro floating point single precision del registro xmm5.
Se continiamo nell'analisi del flusso arriveremo finalmente al codice di checking

.text:0000000000402A8B check_xmm1:                            
.text:0000000000402A8B                                        
.text:0000000000402A8B                 mov     rax, 4160C1h
.text:0000000000402A95                 movzx   eax, word ptr [rax] ;carica la prima word dal buffer del primo file (warning)
.text:0000000000402A98                 nop     dword ptr [rax]
.text:0000000000402A9B                 sub     rsp, 10h
.text:0000000000402A9F                 cvtps2dq xmm1, xmm1 ;converte i floating point in dword
.text:0000000000402AA3                 nop     dword ptr [rax]
.text:0000000000402AA6                 movhps  qword ptr [rsp], xmm1 ;mette in [rsp] la parte alta di xmm1
.text:0000000000402AAA                 movlps  qword ptr [rsp+8], xmm1 ;mette in [rsp+8] la parte bassa di xmm1
.text:0000000000402AAF                 nop     dword ptr [rax]
.text:0000000000402AB2                 pop     r8 ;carica la qword di [rsp]
.text:0000000000402AB4                 pop     r9 ;carica la qword di [rsp+8]
;spezza in due la qword di r8
.text:0000000000402AB6                 mov     r10d, r8d ; r10 ha la seconda parte
.text:0000000000402AB9                 nop     dword ptr [rax]
.text:0000000000402ABC                 shr     r8, 20h ;r8 ha la prima parte
;spezza in due la qword di r9
.text:0000000000402AC0                 mov     r11d, r9d ;r11 ha la seconda parte
.text:0000000000402AC3                 nop     dword ptr [rax]
.text:0000000000402AC6                 shr     r9, 20h ;r9 ha la prima parte
.text:0000000000402ACA                 nop     dword ptr [rax]
;vengono sommate tutte e quattro le dword
.text:0000000000402ACD                 add     r8, r9
.text:0000000000402AD0                 nop     dword ptr [rax]
.text:0000000000402AD3                 add     r8, r10
.text:0000000000402AD6                 add     r8, r11
.text:0000000000402AD9                 and     r8, 0FFFFh
.text:0000000000402AE0                 nop     dword ptr [rax]
.text:0000000000402AE3                 cmp     r8d, eax ;compara la word presa dal primo buffer con la somma delle dword di xmm1
.text:0000000000402AE6                 jnz     loc_403120 ;se i valori non sono uguali esci
.text:0000000000402AEC                 jmp     vai_a_controllare_xmm2

Questo controllo viene effettuato anche per xmm2/xmm3/xmm4.



Possibile soluzione:
Il file Waring dovrà contenere 4 word, una per ogni check, che deve essere ricavata in questa maniera:

[xmm1(1) * xmm5(1)] + [xmm1(2) * xmm5(2)] + [xmm1(3) * xmm5(3)] + [xmm1(4) * xmm5(4)] = WORD(0x20..75,0x20..7a).

A questo punto bisogna trovare un array di quattro floating point single precision che vada bene anche per xmm2/3/4.
Se si guarda la tabella dei valori che hanno i quattro registri dopo aver caricato i vari array, si può notare che il secondo floating point è quello più grande per tutti i registri, quindi basta far in modo che il prodotto del più piccolo di questi, moltiplicato per un numero, arrivi come minimo a 0x2020 e poi si caricano nei restanti tre floating point di xmm5 il valore 1, così da aggiungere i restanti valori, così come sono presenti nella tabella:

[xmm1(1)] + [xmm1(2) * XX] + [xmm1(3)] + [xmm1(4)] = WORD(0x20..75,0x20..7a).

Ora vi faccio vedere il mio "Register a name and a valid serial" in hex (ricordo che i valori sono in little endian):

01 00 00 00 01 00 00 00 10 02 00 00 01 00 00 00

ed ecco il mio "Warning" che in ascii è "ZFP'GD,#", ve lo riporto in hex e ricordatevi del little endian:

5a 46 50 27 47 44 2c 23




Dopo aver risolto il crackme, avendo passato tutti e quattro i check per i registri xmm1/2/3/4, non ci resta che capire dov'è la messagebox dei complimenti: dopo il controllo di xmm4, il flusso del programma arriva a questo punto

.text:00000000004030AB sub_4030AB      proc near              
.text:00000000004030AB                 call    fake_proc
.text:00000000004030B0                 nop     dword ptr [rax]
.text:00000000004030B3                 call    fake_proc
.text:00000000004030B8                 nop     dword ptr [rax]
.text:00000000004030BB                 mov     rsi, cs:exp_dir_UnwindInfoAndress
.text:00000000004030C2                 nop     dword ptr [rax]
.text:00000000004030C5                 mov     rax, 416110h  ;solita storia
.text:00000000004030CF                 call    loc_4030D7
.text:00000000004030D4                 nop     dword ptr [rax]
.text:00000000004030D4
.text:00000000004030D7
.text:00000000004030D7 loc_4030D7:                            
.text:00000000004030D7                 call    fake_proc1
.text:00000000004030DC                 nop     dword ptr [rax]
.text:00000000004030DF                 call    fake_proc1
.text:00000000004030E4                 nop     dword ptr [rax]
.text:00000000004030E7                 sub     rax, cs:ImgBase
.text:00000000004030EE                 mov     [rsi], eax ;solita storia
.text:00000000004030F0                 add     rsp, 10h
.text:00000000004030F0 ; ---------------------------------------------------------------------------
.text:00000000004030F4                 db  60h ;

Dopo l'eccezione generata in 4030f4, il controllo passa in mano al gestore d'eccezione, ed analizzando il flusso, superando il junk code si arriva qua

.text:00000000004038AC decrypt_message:                        ; CODE XREF: .text:00000000004037DD�j
.text:00000000004038AC                                         ; .text:00000000004037E4�j
.text:00000000004038AC                 mov     rsp, [r8+98h]
.text:00000000004038B3                 mov     rdi, 416030h
.text:00000000004038BD
.text:00000000004038BD decrypt_string1:                             ; CODE XREF: .text:00000000004038C7�j
.text:00000000004038BD                 movzx   rax, byte ptr [rdi]
.text:00000000004038C1                 xor     al, 75h
.text:00000000004038C3                 stosb
.text:00000000004038C4                 cmp     byte ptr [rdi], 0
.text:00000000004038C7                 jnz     short loc_4038BD
.text:00000000004038C9                 mov     rdi, 416048h
.text:00000000004038D3                 mov     al, 47h
.text:00000000004038D5
.text:00000000004038D5 decrypt_string2:                             ; CODE XREF: .text:00000000004038D8�j
.text:00000000004038D5                 add     al, [rdi]
.text:00000000004038D7                 stosb
.text:00000000004038D8                 jnz     short loc_4038D5
.text:00000000004038DA                 push    rsp
.text:00000000004038DB                 and     spl, 0F0h
.text:00000000004038DF                 push    7D0h
.text:00000000004038E4                 push    0
.text:00000000004038E6                 mov     r9, 0
.text:00000000004038ED                 mov     r8, 416048h
.text:00000000004038F7                 mov     rdx, 416030h
.text:0000000000403901                 mov     rcx, 0
.text:0000000000403908                 sub     rsp, 20h
.text:000000000040390C                 mov     rax, 403AD3h    ; ret address
.text:0000000000403916                 push    rax
.text:0000000000403917                 nop     dword ptr [rax]
.text:000000000040391A                 jmp     loc_4078FE ; jmp     cs:MessageBoxTimeoutA

E con questo ho concluso.


Conclusione

E' un crackme leggermente bastardello, che m'ha fatto perdere un paio di giorni d'analisi ed una notte per scrivere il tutorial, ma nulla di che: gente alla prossima.
Pnluck


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.