Aspack, UnAspack(già sentito??) |
||
Data |
by "Pnluck" |
|
29/10/2004 |
Published by Quequero |
|
|
Complimenti pn, ti sei dedicato al UIC Packers Project e ne hai fatto un ottimo tute, bravo davvero, continua cosi |
Ke bello riempire gli spazzi vuoti |
.... |
E-mail: [email protected] Pnluck,#crack-it,#pmode,#assembly,#iglug |
.... |
Difficoltà |
(X)NewBies ( )Intermedio ( )Avanzato ( )Master |
Manual Unpacking
di
Aspack
Written by Pnluck
Introduzione |
Analiziamo il packer: Aspack. Troviamo OEP e l’ IT. Cmq un minimo sul PE lo dovreste sapere. Vedete il tute di Nt è ottimo :D
Tools usati |
Tools usati: Ollydbg ,Wark o LordPe
URL o FTP del programma |
Non me lo ricordo, vedete nel forum :D
Notizie sul programma |
Un packer semplice semplice, forse + di upx :D.
Essay |
Analiziamo il prg (qui gli opcode sono importanti):
00438000 90 NOP ; nop 00438001 60 PUSHAD ;salva i seguenti registri eax, ecx, edx, ebx, esp, ebp, esi, edi 00438002 E8 03000000 CALL uic_test.0043800A ;chiama la funzione a 43800A 00438007 -E9 EB045D45 JMP 45A084F7; ke strano jmp 0043800D C3 RETN ;ritorna |
Ora analizziamo tutto da capo, la call punta dentro il codice di quel jmp, quindi qui c’è un piccolo trucco, cmq steppiamo dentro et voilà:
00438008 EB 04 JMP SHORT uic_test.0043800E ; 0043800A 5D POP EBP ; preleva uic_test.00438007 0043800B 45 INC EBP ebx++ 0043800D C3 RETN ,va a 438008 |
La call ci porta a 43800A, qui si prende dallo stack l’indirizzo 438007, all’istruzione successiva si aumenta questo valore di uno (ebp=43008), e fa andare quel retn a 43800D, e poi con quel jmp ci troviamo a 43800E:
0043800E E8 01000000 CALL uic_test.00438014 ;di nuovo lo stesso skerzetto 00438013 EB 5D JMP SHORT uic_test.00438072 ;chi sa ke uscirà fuori :D 00438015 BB EDFFFFFF MOV EBX,-13 ;toglie a ebx -13h |
Ok steppiamo dentro :D
00438014 5D POP EBP ;EBP =00438013 00438015 BB EDFFFFFF MOV EBX,-13 ;questo, 0043801A 03DD ADD EBX,EBP ;questo 00438022 83BD 22040000 00 CMP DWORD PTR SS:[EBP+422],0 ;verifica se è vuoto 00438029 899D 22040000 MOV DWORD PTR SS:[EBP+422],EBX ; gli mette ebx |
Ok, questo processo calcola l’image-base. Andiamo avanti :
00438035 LEA EAX,DWORD PTR SS:[EBP+42E] ;eax = kernel32.dll 0043803B PUSH EAX ;carica eax 00438042 MOV DWORD PTR SS:[EBP+426],EAX ;mette il risultato in [ebp+426] 00438048 MOV EDI,EAX ;e in edx 0043804A LEA EBX,DWORD PTR SS:[EBP+5E] ;ebx=VirtualAlloc 0043804D PUSH EBX ;prende ebx 0043804E PUSH EAX ;eax = handle della dll 00438055 MOV DWORD PTR SS:[EBP+54D],EAX ;ebp+54d = Kernel32.VirtualAlloc 0043805B LEA EBX,DWORD PTR SS:[EBP+6B] ;ebx = VirtualFree 0043805E PUSH EBX ;prende ebx 00438060 CALL DWORD PTR SS:[EBP+F49] ;chiama di nuovo GetProcessAddress 00438066 MOV DWORD PTR SS:[EBP+551],EAX ;ebx = kernel32.VirtualFree |
Questa parte di codice ricava l’indirizzo in memoria di due api: VirtualAlloc e VirtualFree.
La prima riserva una zona in memoria per il processo
La seconda libera una zona virtuale di memoria
Ora se andiamo a vedere l’indirizzo di 40808A, c’è sempre il solito trucchetto, perciò vi riporto direttamente il codice:
0043808A MOV EBX,DWORD PTR SS:[EBP+531] ;ebx=0 00438090 OR EBX,EBX ;se ebx 00438092 JE SHORT uic_test.0043809E ;è zero 00438094 MOV EAX,DWORD PTR DS:[EBX] ;se no eax=ebx 00438096 XCHG DWORD PTR SS:[EBP+535],EAX ;ebp+535= eax 0043809E LEA ESI,DWORD PTR SS:[EBP+569] ;esi= VOffset di .text 004380A4 CMP DWORD PTR DS:[ESI],0 ;se esi = 0 004380A7 JE uic_test.004381CE ;zompa Si prepara x chiamare una dll 004380AD PUSH 4 ;il tipo di protezione 004380AF PUSH 1000;il tipo di allocazione 004380B4 PUSH 1800 ;la grandezza 004380B9 PUSH 0 ;passa l’indirizzo 004380BB CALL DWORD PTR SS:[EBP+54D] chiama VirtualAlloc 004380C1 MOV DWORD PTR SS:[EBP+156],EAX ;ebp+156 = spazio allocato(da 860000) 004380C7 MOV EAX,DWORD PTR DS:[ESI+4] ;eax = VSize di una sezione 004380CA ADD EAX,10E ;eax += 0x10e 004380CF PUSH 4 ;come prima 004380D1 PUSH 1000 ;tipo allocazione 004380D6 PUSH EAX ;grandezza 004380D7 PUSH 0 ;indirizzo 004380D9 CALL DWORD PTR SS:[EBP+54D] ;chiama VirtualAlloc 004380DF MOV DWORD PTR SS:[EBP+152],EAX ;ebp+152 =spazio allocato (da 870000) |
Queste chiamate a VirtualAlloc, creano dello spazio in memoria, dove, vi sarà il codice decriptato, di ogni sezione del prg (formato PE si intende :). Continuiamo
004380E5 PUSH ESI ; 004380E6 MOV EBX,DWORD PTR DS:[ESI] ;ebx = VOffset della sezione 004380E8 ADD EBX,DWORD PTR SS:[EBP+422] ;ebx =imagebase + VOffset 004380EE PUSH DWORD PTR SS:[EBP+156] passa 86000 004380F4 PUSH DWORD PTR DS:[ESI+4] passa la grandezza della sezione, cioè il VSize 004380F7 PUSH EAX passa 87000 cioè dove deve mettere il codice decriptato 004380F8 PUSH EBX e passa dove, deve iniziare a decriptare 004380F9 CALL uic_test.0043866C ;call che decripta una sezione del PE 004380FE MOV BL,0 ;bl = 0 (all’inizio) 00438100 CMP BL,0 ;se non è la prima sezione analizzata 00438103 JNZ SHORT uic_test.00438163 ;salta, se è la sezione .text continua 00438105 INC BYTE PTR SS:[EBP+EC] aumentando il valore del mov con bl. Cioè dopo quel moc bl,0 diviene mov bl,1 etc a seconda delle sezioni |
Ora quella call, non ve la riporto tutta, xkè uscirebbe un libro di 130 pagine, vi dico solo una cosa, vedete 870000 prima e dopo,giusto x vedere se dico cazzate.
Questa call viene richiamata x ogni sezione da decriptare. Avanti:
0043810B MOV EDI,DWORD PTR DS:[ESI] edi = VOffset di .text 0043810D ADD EDI,DWORD PTR SS:[EBP+422] e gli aggiunge l’image base 00438113 PUSH DWORD PTR DS:[EDI] salva edi 00438115 MOV BYTE PTR DS:[EDI],0C3 gli muove c3 cioè un ret 00438118 CALL EDI chiama 401000 0043811A POP DWORD PTR DS:[EDI] e rimette a posto tutto |
Questo è un altro trucchetto, che serve nei casi che impostiamo il rage tra VOffset di .text e .rdata, per trovare l’Entrypoint. Continuiamo:
0043811D PUSH ECX ecx = 1 0043811E PUSH ESI 43857c 00438120 MOV ECX,EAX ecx = eax 00438122 SUB ECX,6 ecx - 6 00438125 MOV ESI,DWORD PTR SS:[EBP+152] esi = 870000 0043812B XOR EBX,EBX ebx = 0 0043812D /OR ECX,ECX se ecx 00438131 |JS SHORT uic_test.0043815F è negative esce, 00438133 |LODS BYTE PTR DS:[ESI] se no, carica in al il valore di esi 00438134 |CMP AL,0E8 se è uguale a E8(call) 00438136 |JE SHORT uic_test.00438142 00438138 |JMP SHORT uic_test.0043813A 0043813A |CMP AL,0E9 se è uguale a E9(long jmp) 0043813E |INC EBX se no, incrementa ebx 00438140 \JMP SHORT uic_test.0043812D e reinizia 00438142 |MOV EAX,DWORD PTR DS:[ESI] mette in eax la dword puntata da esi 00438144 |JMP SHORT uic_test.00438146 (non fa niente) 00438146 |CMP BYTE PTR DS:[ESI],7 se dopo E8 o E9 non c’è 0x07 00438149 |JNZ SHORT uic_test.0043813E 0043814B |AND AL,0 altrimenti fa un AND tra al con 0x00 0043814D |ROL EAX,18 fa un rotate left di 18 00438150 |SUB EAX,EBX eax -= ebx 00438152 |MOV DWORD PTR DS:[ESI],EAX sostituisce il risultato in memoria 00438154 |ADD EBX,5 ebx+5 00438157 |ADD ESI,4 esi+4 0043815A |SUB ECX,5 ecx-5 0043815D \JMP SHORT uic_test.0043812D reinizia 00438160 POP ESI esi = 43857c 00438161 POP ECX rimette a posto ecx 00438162 POP EAX rimette a posto il VSize 00438163 JMP SHORT uic_test.0043816D e |
Questa procedura si ripete finché ecx(che conteniene il VSize di .text) non è zero, poi come capito verifica se c’è un E807 o E907.
Questo controllo avviene solo x la sezione .text.Ora viene il bello dehhihihihho :D
0043816D MOV ECX,EAX ecx = VSize 00438171 ADD EDI,DWORD PTR SS:[EBP+422] edi += imagebase 00438177 MOV ESI,DWORD PTR SS:[EBP+152] esi = 870000(ci sono i file decifrati) 0043817D SAR ECX,2 sar è uno shift aritmetico a destra. Qui divide x 100(10^2) 00438180 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] qui il codice decriptato di una sezione, va a sovrascrivere il codice criptato della stessa. Dopo ciò edi punta al VOffset della prossima sezione.(Raga è un giro di parole, ma abbiate pazienza :) 00438182 MOV ECX,EAX ecx = VSize sezione 00438184 AND ECX,3 azzera ecx 00438187 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] non fa niente 00438189 POP ESI rimette a posto 43857c 0043818A PUSH 8000 00438191 PUSH DWORD PTR SS:[EBP+152] zona memoria da liberare con la 00438197 CALL DWORD PTR SS:[EBP+551] chiamata a VirtualFree 0043819D ADD ESI,8 esi +8 004381A0 CMP DWORD PTR DS:[ESI],0 se abbiamo finito continua con l’IT, 004381A3 JNZ uic_test.004380C7 se no, decripta la prossima sezione |
Questa procedura decripta ogni sezione PE del file in questo modo:
1. Passa alla call in 4380f9, le informazioni della sezione da decriptare cioè dove inizia decriptare(ImageBase+VOffet),la grandezza della sezione(VSize)
2. e dove mettere il codice da decriptare 870000(nel mio caso)
3. Nella call vengono decriptate tutte le sezioni del prg(se decriptiamo la prima sezione cioè .text, verifica la presenza di E807 o E907),e passa alla prossima sezione
4. Se la prossima sezione del prg, ci restituisce valori null, significa che le sezioni sono finite,e passa al prossimo passaggio; altrimenti continua a decriptare.
Continuiamo con la spiegazione:
004381A9 PUSH 8000 004381AE PUSH 0 004381B0 PUSH DWORD PTR SS:[EBP+156] prende la zona in memoria: 860000 004381B6 CALL DWORD PTR SS:[EBP+551] e la libera con VirtualFree 004381BC MOV EBX,DWORD PTR SS:[EBP+531] ebx = 0 004381C2 OR EBX,EBX se ebx = 0 004381C4 JE SHORT uic_test.004381CE 004381C6 MOV EAX,DWORD PTR DS:[EBX] | 004381C8 XCHG DWORD PTR SS:[EBP+535],EAX | 004381CE MOV EDX,DWORD PTR SS:[EBP+422] edx = imagebase( 004381D4 MOV EAX,DWORD PTR SS:[EBP+52D] eax = imagebase(data da win) 004381DA SUB EDX,EAX se edx - eax 004381DC JE SHORT uic_test.00438257 è uguale a zero salta ……………(altro codice che serve x le dll) |
Quel sub controllo se si agisce su un prg, altrimenti è una dll ed il codice che ho lasciato serve (penso) x le dll. Ora inizia il bello l’IT del prg iniziale :D
00438257 MOV EDX,DWORD PTR SS:[EBP+422] edx = imagebase 0043825D MOV ESI,DWORD PTR SS:[EBP+541] esi = 0 00438263 OR ESI,ESI se esi = 0 00438265 JE SHORT uic_test.00438278 salta ……………(altro codice non indispensabile) 00438278 MOV ESI,7F88 0x7f88 è il VirtualAddess dell’IT 0043827D MOV EDX,DWORD PTR SS:[EBP+422] edi = imagebase 00438283 ADD ESI,EDX calcola l’indirizzo dell’IT (rva) 00438285 MOV EAX,DWORD PTR DS:[ESI+C] EAX = Nome della dll analizare 00438288 TEST EAX,EAX se è zero 0043828A JE uic_test.0043839A jmp 00438290 ADD EAX,EDX EAX= imagebase+dll_name 00438292 MOV EBX,EAX ebx = eax 00438294 PUSH EAX Prende EAX 00438295 CALL DWORD PTR SS:[EBP+F4D] e chiama GetModuleHandle 0043829B TEST EAX,EAX se non è zero 0043829D JNZ SHORT uic_test.004382A6 jmp due righe più sotto 004382A0 CALL DWORD PTR SS:[EBP+F51] 004382A6 MOV DWORD PTR SS:[EBP+545],EAX risultato della chiamata: salvato 004382AC MOV DWORD PTR SS:[EBP+549],0 [ebp+549] = 0 004382B6 /MOV EDX,DWORD PTR SS:[EBP+422] EDX = imagebase 004382BC |MOV EAX,DWORD PTR DS:[ESI] EAX = ESI = OriginalFirstThunk della dll 004382BE |TEST EAX,EAX se è diverso da zero 004382C0 |JNZ SHORT uic_test.004382C5 jmp 004382C2 |MOV EAX,DWORD PTR DS:[ESI+10] 004382C5 |ADD EAX,EDX EAX = imagebase+OriginalFirstThunk della dll 004382C7 |ADD EAX,DWORD PTR SS:[EBP+549] EAX += valore di [EBP+549] 004382CD |MOV EBX,DWORD PTR DS:[EAX] EBX = [EAX] = nome della call 004382CF |MOV EDI,DWORD PTR DS:[ESI+10] EDI = FirstThunk dell’api 004382D2 |ADD EDI,EDX EDI = imagebase + FirstThunk 004382D4 |ADD EDI,DWORD PTR SS:[EBP+549] EDI += [ebp+549] 004382DA |TEST EBX,EBX se EBX = 0 004382DC |JE uic_test.00438384 passa alla prossima dll da analizzare 004382E2 |TEST EBX,80000000 se non è uguale a 80000000 004382E8 |JNZ SHORT uic_test.004382EE jmp, altrimenti 004382EA |ADD EBX,EDX EBX = imagebase + call_name 004382EC |INC EBX EBX++ 004382ED |INC EBX EBX++ 004382EE |PUSH EBX passa alla prossima call 004382EF |AND EBX,7FFFFFFF gli fa un and 004382F5 |PUSH EBX prende EBX 004382F6 |PUSH DWORD PTR SS:[EBP+545] prende l’indirizzo in memoria della dll, ke richiama la call 004382FC |CALL DWORD PTR SS:[EBP+F49] e chiama GetProcAddr 00438302 |TEST EAX,EAX se il risultato nam_dll.call_nam(es: user32.EnableWindow) non è zero 00438304 |POP EBX 00438305 |JNZ SHORT uic_test.00438376 salta …………………..(codice inutile x decriptare un prg) 00438376 |MOV DWORD PTR DS:[EDI],EAX sovrascrive il valore di edi(punta all’IAT) 00438378 |ADD DWORD PTR SS:[EBP+549],4 [ebp +594] += 4 : prossima call 00438384 MOV DWORD PTR DS:[ESI],EAX OFT= 0 00438386 MOV DWORD PTR DS:[ESI+C],EAX Name_dll = 0 00438389 MOV DWORD PTR DS:[ESI+10],EAX FT = 0 00438395 JMP uic_test.00438285 ritorna a 438285 |
Quest’ultima parte di codice lavora con l’ IT del prg packato, ho intuito ciò xkè vedevo i nomi delle dll :P, cmq poi andando all’indirizzo dell’IT ho visto che quei byte potevano essere quelli dell’Import Table, dato ke ci sono 2 dword vuote(TimeDateStamp e FowarderChain) . Cmq credo che il procedimento sia chiaro. Prende dall’IT l’indirizzo della prima dll, poi man mano lavora con le call, prendedo gli indirizzi in memoria di queste e le sostituisce con quelli dell ‘IAT originale.
Quando arriva ad una dword vuota passa, alla prossima dll, e fa lo stesso lavore con le call di questa, fino a quando trova una dword vuota, lì dove ci dovrebbero essere le informazioni della Import Table di una dll, e va avanti nel decriptino del prg. Ora troviamo l’OEP (Original Entry Point).
0043839A MOV EAX,12A5 0x12A5 è il VA dell’entry point 004383A0 ADD EAX,DWORD PTR SS:[EBP+422] gli aggiunge l’imagebase 004383A6 POP ECX carica ecx 004383A7 OR ECX,ECX e fa un bel OR 004383A9 MOV DWORD PTR SS:[EBP+3A8],EAX mette l’OEP
al posto di quell “push 004383AF POPAD rimette a posto i valore che c’erano quando è stato lanciato il prg 004383B0 JNZ SHORT uic_test.004383BA Se ecx è diverso da zero continua(dovrebbe jmpare sempre) 004383B2 MOV EAX,1 004383B7 RETN 004383BA PUSH 0 questo push diventa: “PUSH uic_test.004012A5”, e mette in ESP l’indirizzo dell’OEP 004383BF RETN e ritorna, all’indirizzo indicato da ESP. |
Da dopo il RET, ci dovrebbe essere il prg unpackato, ora in olly, rianalizatte tutto e dovreste vedere il codice in chiaro :D
Evvai, abbiamo finito =); ora facciamo un breve sommario
Manual Unpacking
Ora sappiamo dov’è l’ OEP e l’indirizzo dell’IT, ora non ci resta che dumparlo prima che lavori con l’IT.
Quindi lo dobbiamo far “freezare”, prima che avvenga ciò, lo possiamo anche appena finisce il decript,io ho deciso di farlo freezare a 00438278.
Se aveto il plug-in commandline di quequero (lo trovate sul forum che e' ancora in fase beta NdQue), non vi basta che andare a quest’indirizzo e digitare “eip eip”, ora premete F9 in Olly, x lanciate il prg, , lanciate wark o lordPE, e dumpate il programma.
Ora aprite il file con un editor PE, e cambiate EntryPoint con 12A5, poi andate alla Directory Table, e azzerate il Relocation, e cambiate IT con il valore trovato, cioè 7F88, xò c’è pure la grandezza, come la calcoliamo??? Semplice Import Table, e composta da 5 Dword.
Ora x vedere quante dll ci sono, basta prendere il RA del name della prima dll, e cercare in quel gruppo, nomi che terminano con “.DLL”.
Quindi basta fare dalla calcolatrice 4*5*(numero delle dll) e convertire tutto in hex, ora in questo caso è 4*5*2 = 40 = 0x28. Ora salviamo tutto, e lanciamo il prg, e tatà parte :D
Ora alleggeriamolo un po’, cancelliamo la sezione .aspack e .adata.
Finito
Pnluck
Note finali |
Grazie ai ragazzi della uic, B0, Geo, Fego, Ged x il suo tute su aspack ke mi ha aiutato un po’, Saturn e tutti gli altri che mi hanno aiutato. Poi i miei boss Nt e Quake :D
Disclaimer |
Qui inserirete con questo carattere il vostro piccolo disclaimer, non è obbligatorio però è meglio per voi se c'è. Dovete scrivere qualcosa di simile a: vorrei ricordare che il software va comprato e non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento è stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.