Win64 BeaBA crackme
From UIC
BeatriX's BeaBA solution
Contents |
| Infos | |
|---|---|
| Author: | Pnluck |
| Email: | |
| Website: | http:\\pnluck.netsons.org |
| Date: | 22/07/2008 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| 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
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: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:
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ò:
Andate all'indirizzo indicato del terzo membro, che sarebbe l'indirizzo che ha la struttura UNWIND_INFO
.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ì
;...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: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 ; .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 ; .text:00000000004014B7�j
.text:0000000000401521 db 36h ; 6
.text:0000000000401522 db 10h
Quindi andiamo ad analizzare il codice all'indirizzo 401721:
.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 ; .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 ; .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
.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
.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: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:
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
.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:
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:
Ora vi faccio vedere il mio "Register a name and a valid serial" in hex (ricordo che i valori sono in little endian):
ed ecco il mio "Warning" che in ascii è "ZFP'GD,#", ve lo riporto in hex e ricordatevi del little endian:
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 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 ; .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.