Lezione8 SepticConvulsion solution
From UIC
Soluzione Lezione 8 for Newbie 2009
Contents |
| Infos | |
|---|---|
| Author: | SepticConvulsion |
| Email: | septicconvulsion@gmail.com |
| Website: | |
| Date: | 12/12/2008 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | |
Introduzione
Bel tute quello di §-Death_Reaver-§. Ho iniziato a leggerlo sbruffoneggiando e sono finito a fare il crackme prendendomi due o tre attacchi di cuore. Cosi' imparo a fare il figo :P
Il codice che segue e' praticamente pieno di label ... che vi devo dire, io le uso sempre e penso aiutino molto :)
Tools
OllyDBG 1.10
Filemon 7
Regmon 7
Guida API
Link e Riferimenti
Questo è la soluzione del CrackmeLezione8 disponibile alla pagina Lezione_8_File_and_Registry_Keys
Essay
Come prima operazione e' saggio mettere una label sugli indirizzi di "fallimento". Ovvero: andare all'indirzzo in cui tutti i jump mandano quando un test e' fallito e metterci una bella label che vi ricordi che queste istruzioni non sono da eseguire. Questo vi permettera' di capire a priori quali sono i salti condizionali che NON vanno fatti e, di conseguenza, quali sono le condizioni da soddisfare per passare i vari test. Nel mio caso ho labellato le istruzioni 004001556 e 0040154A come "fine_check" e "closehandle_fine": saltare a queste istruzioni significa che il requisito 3 non era stato assolto. Nella figura seguente vedete come appaiono i jump che non vanno presi.
Iniziamo ad analizzare il codice come suggeritoci da §-Death_Reaver-§
0040129D . |8A10 MOV DL,BYTE PTR DS:[EAX] ; DL = stringa3(ECX)
0040129F . |F6D2 NOT DL
004012A1 . |FEC2 INC DL ; DL = not( stringa3(ECX) ) + 1
004012A3 . |41 INC ECX ; ECX++
004012A4 . |83F9 12 CMP ECX,12 ; ECX == 18.?
004012A7 . |8810 MOV BYTE PTR DS:[EAX],DL
004012A9 .^\7C EC JL SHORT Lezione7.00401297
004012AB . 803D 6C304000>CMP BYTE PTR DS:[<stringa3>],31 ; sempre vero
004012B2 . 75 1C JNZ SHORT <Lezione7.mod3_3> ; mod3_2
004012B4 . 33C0 XOR EAX,EAX ; EAX = 0
004012B6 > 8080 6C304000>ADD BYTE PTR DS:[EAX+<stringa3>],0F ; stringa(EAX) += 0Fh
004012BD . 40 INC EAX ; EAX++
004012BE . 83F8 12 CMP EAX,12 ; EAX == 18.?
004012C1 .^ 7C F3 JL SHORT Lezione7.004012B6
004012C3 . 803D 76304000>CMP BYTE PTR DS:[<check3_2>],58 ; sempre vero
004012CA . 0F85 7A020000 JNZ <Lezione7.closehadle_fine>
004012D0 > > 33C9 XOR ECX,ECX
004012D2 . 894C24 20 MOV DWORD PTR SS:[ESP+20],ECX
004012D6 > 8D05 6C304000 LEA EAX,DWORD PTR DS:[<stringa3>] ; mod3_3
004012DC . 034424 20 ADD EAX,DWORD PTR SS:[ESP+20] ; EAX => stringa3(ECX)
004012E0 . C008 02 ROR BYTE PTR DS:[EAX],2 ; ror stringa(ECX)
004012E3 . 80B1 6C304000>XOR BYTE PTR DS:[ECX+<stringa3>],63 ; stringa(ECX) XOR 63h
004012EA . 41 INC ECX ; ECX++
004012EB . 83F9 12 CMP ECX,12 ; ECX == 12h?
004012EE . 894C24 20 MOV DWORD PTR SS:[ESP+20],ECX
004012F2 .^ 7C E2 JL SHORT Lezione7.004012D6
Bene, il codice qui sopra consiste principalmente in 3 cicli for che mofidicano tutti i caratteri di "stringa3". Ognuno appare con una sintassi diversa, ma tutti e tre usano ECX come contatore dei cicli fatti e EAX per puntare alle varie entry dell'array. Notare che inizialmente stringa3 contiene dei valori che sembrano insensati.
Il primo for (00401297) usa EAX per puntare ogni elemento dell'array: la mette in DL, la nega, ci aggiunge uno e quindi lo riscrive. Il secondo prende un byte per volta e ci aggiunge 0F.
Il terzo for (004012D0) sembra apparentemente diverso, ma in realta' il funzionamento e' sempre lo stesso! In questo caso viene utilizzato lo stack all'indirizzo "ESP+20" per fare puntare EAX alle entry dell'array.
Dopo aver analizzato bene questo codice, ci rendiamo conto che non c'e' necessita' intervenire qui: non c'e' nessuna possibilita' ne di alterare la stringa iniziale, ne possibilita' di fallimenti (infatti non ci sono jmp a inidirizzi di fallimento). Dobbiamo semplicemente fare eseguire questi tre cicli e, partendo da una sequenza di caratteri incomprensibili, ritroveremo in "stringa3" il seguente path "setup\texture.dat". In pratica i cicli serivano a decrittare la stringa originale! Andando avanti con il disassemblato troviamo:
004012F6 . 53 PUSH EBX ; |c
004012F7 . 57 PUSH EDI ; |s
004012F8 . E8 45030000 CALL <JMP.&MSVCR80.memset> ; \memset
004012FD . 6A 0A PUSH 0A ; /n = A (10.)
004012FF . 53 PUSH EBX ; |c
00401300 . 68 C0344000 PUSH OFFSET <Lezione7.buf_reg2> ; |s = OFFSET <Lezione7.buf_reg2>
00401305 . E8 38030000 CALL <JMP.&MSVCR80.memset> ; \memset
0040130A . 83C4 18 ADD ESP,18 ; azzera buffer_reg e buffer
0040130D . E8 C3020000 CALL <Lezione7.trova_driver> ; AL = 0, no driver
00401312 . 84C0 TEST AL,AL
00401314 . 0F84 3C020000 JE <Lezione7.fine_check>
I due memset servono ad azzerare i dati contenuti nei due buffer. In 0040130D abbiamo una chiamata alla funzione "trova_driver" seguita da un test sul valore restituito. Da qui e' gia' presumibile che la funzione debba restituire un valore diverso da zero se non si vuole causare la fine del test.
Analizziamo il codice di "trova_driver":
004015DC |. 56 PUSH ESI
004015DD |. 77 20 JA SHORT <Lezione7.non_trovato_drive> ; critted_path2(0) > 5A salta
004015DF |. BE 68304000 MOV ESI,OFFSET <Lezione7.driver> ; ASCII "H:\\"
004015E4 |> FE05 68304000 /INC BYTE PTR DS:[<driver>] ; critted_path2(0)++ = cambia la lettera del drive
004015EA |. 56 |PUSH ESI ; /RootPathName
004015EB |. FF15 30204000 |CALL DWORD PTR DS:[<&KERNEL32.GetDriveTypeA>] ; \GetDriveTypeA
004015F1 |. 83F8 05 |CMP EAX,5 ; 5 = cd_rom?
004015F4 |. 74 13 |JE SHORT <Lezione7.trovato_drive>
004015F6 |. 803D 68304000>|CMP BYTE PTR DS:[<driver>],5A ; drive == 'Z'?
004015FD |.^ 76 E5 \JBE SHORT Lezione7.004015E4
004015FF >|> FE05 68304000 INC BYTE PTR DS:[<driver>]
00401605 |. 32C0 XOR AL,AL
00401607 |. 5E POP ESI
00401608 |. C3 RETN
00401609 >|> 56 PUSH ESI ; /src
0040160A |. BE F4344000 MOV ESI,OFFSET <Lezione7.path3_valido> ; |
0040160F |. 56 PUSH ESI ; |dest => OFFSET <Lezione7.path3_valido>
00401610 |. E8 27000000 CALL <JMP.&MSVCR80.strcpy> ; \strcpy
00401615 |. 68 6C304000 PUSH OFFSET <Lezione7.stringa3> ; /src = "setup\\texture.dat"
0040161A |. 56 PUSH ESI ; |dest
0040161B |. E8 28000000 CALL <JMP.&MSVCR80.strcat> ; \strcat
00401620 |. 83C4 10 ADD ESP,10
00401623 |. B0 01 MOV AL,1
00401625 |. 5E POP ESI
Si comincia controllando se la variabile "driver" sia uguale a 'Z'. In talcaso si restituisce 0 e finisce tutto li. Altrimenti si continua e si finisce nel ciclo for all'inirizzo 004015E4.
004015EA |. 56 |PUSH ESI ; /RootPathName
004015EB |. FF15 30204000 |CALL DWORD PTR DS:[<&KERNEL32.GetDriveTypeA>] ; \GetDriveTypeA
004015F1 |. 83F8 03 |CMP EAX,5 ; 5 = cd_rom?
004015F4 |. 74 13 |JE SHORT <Lezione7.trovato_drive>
004015F6 |. 803D 68304000>|CMP BYTE PTR DS:[<driver>],5A ; drive == 'Z'?
004015FD |.^ 76 E5 \JBE SHORT Lezione7.004015E4
Il ciclo scorre tutte le lettere a partire da 'H:' a 'Z:' (incrementando "driver") e, tramite la API "GetDriveTypeA", ottiene in EAX la tipologia del drive corrispondente: se si tratta di un cd-rom (EAX==5) si passa alla seconda parte della funzione. Altrimenti, una volta giunti al driver 'Z:', la funzione restituisce 0 e il check fallisce.
0040160A |. BE F4344000 MOV ESI,OFFSET <Lezione7.path3_valido> ; |ASCII "C:\\setup\\texture.dat"
0040160F |. 56 PUSH ESI ; |dest => OFFSET <Lezione7.path3_valido>
00401610 |. E8 27000000 CALL <JMP.&MSVCR80.strcpy> ; \strcpy
00401615 |. 68 6C304000 PUSH OFFSET <Lezione7.stringa3> ; /src = "setup\\texture.dat"
0040161A |. 56 PUSH ESI ; |dest
0040161B |. E8 28000000 CALL <JMP.&MSVCR80.strcat> ; \strcat
00401620 |. 83C4 10 ADD ESP,10
00401623 |. B0 01 MOV AL,1
00401625 |. 5E POP ESI
00401626 \. C3 RETN
Questa parte copia l'identificativo del drive cd-rom trovato in "path3_valido" e ci incolla dopo la stringa che e' stata decrittata da 00401297 a 004012F2 ("striga3"). Infine restituisce 1 (good!).
Riflettiamo su quanto si deve fare per passare questo check: lui cerca un drive cd-rom e, come vedremo dopo, cerchera' di leggerci qualche file. Quindi in teoria si dovrebbe avere un drive cd-crom assegnato ad una lettera da 'I:' a 'Z:' con dei dati scritti dentro. Il problema puo' essere risolto in molti modi (per esempio usare dei virtual drive, masterizzarsi dei cd), ma io da buon pigrone ho deciso semplicemente di modificare il programma nel seguente modo:
in
In questo modo al posto di partire da 'H:', noi forziamo il ciclo for ad iniziare da 'B:' (42h = 'B' in ascii), che poi verra' incrementato a 'C:' prima della chiamata a GetDriveTypeA. Ho scelto di sovrascrivere proprio quel CMP perche' era l'unica istruzione di una lunghezza adatta che si trovasse prima della chiamata a GetDriveTypeA. Poi ho noppato il JA all'indirizzo 004015DD (tanto senza il CMP non serve piu'). Infine, un' ultima modifica:
in
Con le precedenti modifiche la funzione cerchera' un hart-disk (codice 03) e, come primo tentativo, trovera' 'C:'. Cosi' posso tranquillamente lavorare sul mio hd normale senza tirare di mezzo cd e mazzi vari :) Quindi in "path3_valido" viene storato, nel mio caso, "C:\\setup\\texture.dat". Non so se andare a pathcare un crackme sia una cosa molto elegante, ma onestamente non avevo la minima voglia di tirare in mezzo cd e virtual drive e questa soluzione mi dava molto piu' controllo sul file da inserire.
Torniamo al codice principale.
0040131B . 68 80000000 PUSH 80 ; |Attributes = NORMAL
00401320 . 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
00401322 . 53 PUSH EBX ; |pSecurity
00401323 . 53 PUSH EBX ; |ShareMode
00401324 . 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ
00401329 . 68 F4344000 PUSH OFFSET <Lezione7.path3_valido> ; |FileName = ""
0040132E . FF15 34204000 CALL DWORD PTR DS:[<&KERNEL32.CreateFileA>] ; \CreateFileA
00401334 . 83F8 FF CMP EAX,-1
00401337 . A3 DC334000 MOV DWORD PTR DS:[<office_hand>],EAX
0040133C . 0F84 14020000 JE <Lezione7.fine_check>
00401342 . 53 PUSH EBX ; /pOverlapped
00401343 . 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] ; |
00401347 . 51 PUSH ECX ; |pBytesRead
00401348 . 6A 14 PUSH 14 ; |BytesToRead = 14 (20.)
0040134A . 57 PUSH EDI ; |Buffer
0040134B . 50 PUSH EAX ; |hFile
0040134C . FF15 10204000 CALL DWORD PTR DS:[<&KERNEL32.ReadFile>] ; \ReadFile
00401352 . 57 PUSH EDI ; /s
00401353 . E8 DE020000 CALL <JMP.&MSVCR80.strlen> ; \strlen
00401358 . 83F8 10 CMP EAX,10
0040135B . 59 POP ECX
0040135C . 0F85 E8010000 JNZ <Lezione7.closehadle_fine>
Si richiama CreateFileA per aprire un file, il cui path e' salvato in "path3_valido". Se non trova nulla (EAX = -1) ci si fotte. Altrimenti in 0040134C si fa una ReadFile e si mette il contenuto in "buffer". La strlen seguente e il CMP fanno capire chiaramene che il file deve contenere almeno 16 caratteri (10h): metteteli!
A seguire ... un bellissimo delirio di test sulla stringa appena immessa! Nel codice seguente tutti gli indirizzi si riferiscono ad entry di "buffer". Io ho labellato ogni byte in oridine crescente, in modo da rendere piu' facile la lettura. Per es. bu12 = 12a entry di buffer. Con un po' di occhio si capisra' che, per ottenre un codice valido, non dobbiamo fare altro che risolvere un sistema di equazioni lineari: le incognite saranno le entry di "buffer" e le uguaglianze sono imposte dai vari CMP.
00401369 . |0F85 DB010000 JNZ <Lezione7.closehadle_fine>
0040136F . |A0 04344000 MOV AL,BYTE PTR DS:[<bu12>]
00401374 . |3805 FE334000 CMP BYTE PTR DS:[<bu6>],AL
0040137A . |0F85 CA010000 JNZ <Lezione7.closehadle_fine>
00401380 . |8A0D 06344000 MOV CL,BYTE PTR DS:[<bu14>]
00401386 . |3AC1 CMP AL,CL
00401388 . |0F85 BC010000 JNZ <Lezione7.closehadle_fine>
0040138E . |8A15 FF334000 MOV DL,BYTE PTR DS:[<bu7>]
00401394 . |3A15 03344000 CMP DL,BYTE PTR DS:[<bu11>]
0040139A . |0F85 AA010000 JNZ <Lezione7.closehadle_fine>
004013A0 . |803D FA334000 66 CMP BYTE PTR DS:[<bu2>],66
004013A7 . |0F85 9D010000 JNZ <Lezione7.closehadle_fine>
004013AD . |803D 07344000 72 CMP BYTE PTR DS:[<bu15>],72
004013B4 . |0F85 90010000 JNZ <Lezione7.closehadle_fine>
004013BA . |803D 02344000 72 CMP BYTE PTR DS:[<bu10>],72
004013C1 . |0F85 83010000 JNZ <Lezione7.closehadle_fine>
004013C7 . |803D FC334000 69 CMP BYTE PTR DS:[<bu4>],69
004013CE . |0F85 76010000 JNZ <Lezione7.closehadle_fine>
Un modo veloce per capire il valore corretto di ogni entri e' vedere i CMP. Questi ci dicono che:
bu12 = bu6 = bu14
bu7 = bu11
bu2 = 66h
bu15 = 72h
bu10 = 72h
bu4 = 69h.
Beeene, ora:
004013D7 . 0FB6C0 MOVZX EAX,AL
004013DA . 03C8 ADD ECX,EAX
004013DC . 0FB605 FE334000 MOVZX EAX,BYTE PTR DS:[<bu6>]
004013E3 . 03C8 ADD ECX,EAX
004013E5 . 81F9 2F010000 CMP ECX,12F
004013EB . 0F85 59010000 JNZ <Lezione7.closehadle_fine>
L'operazione fatta e':
004013F8 . 8D48 A0 LEA ECX,DWORD PTR DS:[EAX-60]
004013FB . 83F9 0F CMP ECX,0F
004013FE . 0F85 46010000 JNZ <Lezione7.closehadle_fine>
Si inizia con EAX = bu9. Poi si prende l'indirizzo puntato da bu9-60h e lo si mette in ECX. ECX deve essere uguale a 0Fh. In pratica si fa
0040140B . 2BC1 SUB EAX,ECX
0040140D . 0F85 37010000 JNZ <Lezione7.closehadle_fine>
00401413 . 33C9 XOR ECX,ECX
00401415 . 33C0 XOR EAX,EAX
00401417 > 0FB690 F8334000 MOVZX EDX,BYTE PTR DS:[EAX+<buffer>]
0040141E . 03CA ADD ECX,EDX
00401420 . 40 INC EAX
00401421 . 83F8 11 CMP EAX,11
00401424 .^ 7C F1 JL SHORT Lezione7.00401417
00401426 . 81F9 A4060000 CMP ECX,6A4
0040142C . 0F85 18010000 JNZ <Lezione7.closehadle_fine>
La sub fa in modo che:
Poi c'e' un for che fa la somma di tutti i valori contenuti in buffer: tale somma deve essere 64A.
Ci sono vari modi per risolvere questo sistema: uno e prendere tutte le equazioni, buttarle dentro un programma di soluzione matematica e vedere cosa ci dice. Molto probabilmente vi dira' che il sistema ha infinite soluzioni, in quanto ci sono diverse variabili libere (se non sbaglio sono 4 o 5). Se non sapete cosa vuol dire andate a farvi un giro su wikipedia. In ogni caso io una soluzione adatta l'ho trovata
00401437 . 68 19000200 PUSH 20019
0040143C . 53 PUSH EBX
0040143D . 68 54214000 PUSH Lezione7.00402154 ; ASCII "perche\\qualcuno\\le_ha\\colpite"
00401442 . 56 PUSH ESI
00401443 . FFD5 CALL EBP
00401445 . 85C0 TEST EAX,EAX
00401447 . 0F85 FD000000 JNZ <Lezione7.closehadle_fine>
0040144D . 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+18]
00401451 . 50 PUSH EAX ; /pBufSize
00401452 . BE C0344000 MOV ESI,OFFSET <Lezione7.buf_reg2> ; |
00401457 . 56 PUSH ESI ; |Buffer => OFFSET <Lezione7.buf_reg2>
00401458 . 8D4424 24 LEA EAX,DWORD PTR SS:[ESP+24] ; |
0040145C . 50 PUSH EAX ; |pValueType
0040145D . 53 PUSH EBX ; |Reserved
0040145E . 57 PUSH EDI ; |ValueName
0040145F . FF35 D8334000 PUSH DWORD PTR DS:[<handle_reg>] ; |hKey = 44
00401465 . C74424 30 23000000 MOV DWORD PTR SS:[ESP+30],23 ; |
0040146D . FF15 04204000 CALL DWORD PTR DS:[<&ADVAPI32.RegQueryValueE>; \RegQueryValueExA
00401473 . 85C0 TEST EAX,EAX
00401475 . 0F85 CF000000 JNZ <Lezione7.closehadle_fine>
0040147B . FF35 D8334000 PUSH DWORD PTR DS:[<handle_reg>] ; /hKey = 00000044 (window)
00401481 . FF15 08204000 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKey>] ; \RegCloseKey
00401487 . 837C24 1C 03 CMP DWORD PTR SS:[ESP+1C],3
0040148C . 0F85 B8000000 JNZ <Lezione7.closehadle_fine>
Questo codice e' gia' stato praticamente spiegato nella lezione 7. In 00401443 apriamo la key "perche\\qualcuno\\le_ha\\colpite" con una chiamata a OpenKeyRegExA (il suo indirizzo e' salvato alla base dello stack). Poi chiamiamo RegQueryValueExA per leggere un valore dal registri: il nome del valore e' proprio la stringa che abbiamo messo in "buffer". Allora basta prendere i valori ascii di "buffer" e creare un valore (di tipo binario, vedi 00401487) con tale nome. Il contenuto del valore del registro verra' messo in buf_reg2. Con il mio codice, fatto apposta per avere tutti caratteri ascii validi, il valore si chiamera' "sofqipeXporXeper".
Bene, ora passiamo ai check sul contenuto del registro.
00401497 . 8BF8 MOV EDI,EAX
00401499 . A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ; [ESI] = [EDI]
0040149A . 66:A5 MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
0040149C . BE C6344000 MOV ESI,Lezione7.004034C6
004014A1 . BF 18354000 MOV EDI,OFFSET <Lezione7.buf_reg2_2>
004014A6 . A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
004014A7 . 66:A5 MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
004014A9 . BE CC344000 MOV ESI,Lezione7.004034CC
004014AE . BF 20354000 MOV EDI,OFFSET <Lezione7.buf_reg2_3>
004014B3 . A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
004014B4 . 66:A5 MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
004014B6 . BE D2344000 MOV ESI,Lezione7.004034D2
004014BB . BF 28354000 MOV EDI,OFFSET <Lezione7.buf_reg_2_4>
004014C0 . A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
004014C1 . 66:A5 MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
004014C3 . BD 30354000 MOV EBP,OFFSET <Lezione7.buf_reg2_5>
004014C8 . BE D8344000 MOV ESI,Lezione7.004034D8
004014CD . 8BFD MOV EDI,EBP
004014CF . A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
004014D0 . 66:A5 MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
Orbene, questa parte di codice sposta gruppi di 6 byte da buf_reg2 alle varie locazioni identificate con buf_reg2_x. Se eseguidte direttamente a 004014D0 e fate un dump della memoria nelle vicinanze di buf_reg2_1, vedrete che ha semplicemente riscritto il contenuto di buf_reg2 spaziando ongi 6 byte con 2 byte a 00.
004014D9 . FFD6 CALL ESI ; \atoi
004014DB . A3 E4334000 MOV DWORD PTR DS:[<atoi1>],EAX
004014E0 . C70424 183540>MOV DWORD PTR SS:[ESP],OFFSET <Lezione7.buf_reg2_2> ; ASCII "000000"
004014E7 . FFD6 CALL ESI
004014E9 . A3 F4334000 MOV DWORD PTR DS:[<atoi2>],EAX
004014EE . C70424 203540>MOV DWORD PTR SS:[ESP],OFFSET <Lezione7.buf_reg2_3> ; ASCII "089434"
004014F5 . FFD6 CALL ESI
004014F7 . A3 E0334000 MOV DWORD PTR DS:[<atoi3>],EAX
004014FC . C70424 283540>MOV DWORD PTR SS:[ESP],OFFSET <Lezione7.buf_reg_2_4> ; ASCII "000000"
00401503 . FFD6 CALL ESI
00401505 . 55 PUSH EBP
00401506 . A3 F0334000 MOV DWORD PTR DS:[<atoi4>],EAX
0040150B . FFD6 CALL ESI
Ora si prendono tutti i gruppi di 6 byte e li si trasformano da stringhe di caratteri ascii a degli interi (usando atoi), e li si scrivono rispettivamente nelle DWORD atoiX (X tra 1 e 5). Se la stringa da trasformare non rappresenta un numero viene scritto 0.
00401514 . 59 POP ECX
00401515 . 59 POP ECX
00401516 . A3 E8334000 MOV DWORD PTR DS:[<atoi5>],EAX
0040151B . 75 2D JNZ SHORT <Lezione7.closehadle_fine>
0040151D . 8B15 E0334000 MOV EDX,DWORD PTR DS:[<atoi3>]
00401523 . 8B0D F4334000 MOV ECX,DWORD PTR DS:[<atoi2>]
00401529 . 2BD1 SUB EDX,ECX
0040152B . 81C2 C4080000 ADD EDX,8C4
00401531 . 81FA 1E660100 CMP EDX,1661E ; a3-a2+8C4h==1161Eh
00401537 . 75 11 JNZ SHORT <Lezione7.closehadle_fine>
00401539 . 8B15 F0334000 MOV EDX,DWORD PTR DS:[<atoi4>]
0040153F . 03C2 ADD EAX,EDX ; a4+a5==a2
00401541 . 3BC1 CMP EAX,ECX
00401543 . 75 05 JNZ SHORT <Lezione7.closehadle_fine>
Ok, qui si arriva effettivamente al controllo. 0040150D controlla che il trentesimo carattere (buf_reg2[29]) sia '\'. Vuol dire che il contenuto del registro deve essere di 29 caratteri piu' '\' finale. Dopo, il valore convertito dell'ultimo gruppo di 6 caratteri viene messo in "atoi5". Le istruzioni da 0040151D a 00401531 e da 00401539 a 00401541 ci dicono:
atoi5 + atoi4 = atoi2
Anche in questo caso ci troviamo davanti ad un sistema lineare con molte soluzioni valide (quattro variabili su due equazioni). Io per pigrizia ho fatto scegliere
atoi3 = 1661E - 8C4 = 15D5A = 089434 (in decimale)
Atoi1 non viene controllata, quindi si puo' mettere quello che si vuole, cosi' come per atoi5, che conta solo che l'ultimo carattere sia '\'.
La parte seguente di disassemblato punta semplicemente a fare apparire i check nella finestra degli obbiettivi del programma. Quindi il crackme e' finito!
Note Finali
Se avete commenti e/o correzioni contattatemi pure via mail o in pm sul forum. Un grosso ringraziamento alla UIC per il corso: continuate cosi! Aspetto con impazienza le prossime lezioni.
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.