Aspack 2.12 automatic unpacking |
||
Data |
by "Pnluck" |
|
29/10/2004 |
Published by Quequero |
|
|
Bravo pn, non ti conveniva checkare per una qualche signature invece di leggere direttamente il nome della sezione? :) Bravo davvero. |
Ke bello riempire gli spazi vuoti |
.... |
E-mail: [email protected] Pnluck,#crack-it,#pmode,#cryptorev#assembly,#iglug |
.... |
Difficoltà |
()NewBies (X)Intermedio (X)Avanzato ( )Master |
Manual Unpacking
di
Aspack
Written by Pnluck
Introduzione |
Per fare un automatic unpacking dovreste avere le conoscenze di minimo 3 cose, c\c++, api per debug, e api per Pe.
Per il primo ci vuole un buon libro, per il secondo grazie a Bender0 e Faina (due grandi :) stanno uscendo grandissimi tute sull’argomento, per il PE bè non saprei dove trovare un tute, ahh si c’è un tute mediocre di Nt, che consiglio di leggere
Tools usati |
Tools usati: Ollydbg , dev-cpp o qualche compilatore + leim :D
URL o FTP del programma |
Non me lo ricordo, vedete nel forum :D
Notizie sul programma |
Aspack 2.12 che dire di + :D
Essay |
Ok, questa è la seconda parte del mio tute sull’aspack 2.12, qui cercheremo di creare un automatic unpacking.
Per prima cosa dobbiamo trovare l’OEP e l’IT del prg da unpackare, se avete letto il mio tute precedente avete capito che è una cosa semplice.
Infatti RVA dell’OEP e dell’IT si trova aggiungendo imagebase+VirtuaAddress(.aspack) + 0x39B(x l’OEP)/0x279(x l’IT).
Cmq x approfondimenti vedete il tute di apack che c’(spero che Nt l’abbia messo) al sito pmode.
Allora noi dobbiamo fare ciò :
Procediamo con ordine, iniziamo con il primo passo:
1
#include<windows.h> //lavorando con PE e dato che dobbiamo fare un debug ci servirà #include<stdio.h> //dobbiamo pure allocare qualcosa in memoria o stampare a schermo qualcosa int main() { HANDLE hFile; //handle FILE *pFile; //ci servirà per prelevare l’it e l’oep BYTE *BaseAddress; //ci servirà per allocare in memoria BYTE x,sezmen; //variabile di supporto e le sezioni da lavare DWORD OffsetOEP,OffsetIT,addrOEP,addrIT; //leggete e capite BYTE aspdir = 0; //qui metteremo il posto di aspack nella section table DWORD it = 0x279; //come ditto l’it DWORD oep = 0x39b; //l’oep DWORD int3 = 0xCC; //Per piazzare un bp DWORD buffer,imagebase; //buffer e imagebase DWORD size=0; //grandezza file da dumpare DWORD FileSize,rawsize,VA; //grandezza del file, offset e VA della sezione pe .aspack DWORD BR, BW,brw; char NomeFile[15]; //Per il PE IMAGE_DOS_HEADER *ImageDosHeader; IMAGE_NT_HEADERS *ImageNtHeaders; IMAGE_SECTION_HEADER *ImageSectionHeader; //Per debug STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi) ); DEBUG_EVENT DebugEv; DWORD dwContinueStatus; CONTEXT context; printf("\n\nUnaspack for aspack 2.12 by Pnluck\n\n"); //si prega di non rimuoverlo :D printf("Inserisci il file criptato con aspack: "); scanf("%s",NomeFile); printf("\nInizio analisi...\n\n"); hFile = CreateFile(NomeFile,GENERIC_READ, FILE_SHARE_READ,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { printf("Non posso aprire il file\n"); return -1; } FileSize = GetFileSize(hFile,NULL); BaseAddress = (BYTE *) malloc(FileSize); if(!ReadFile(hFile,BaseAddress,FileSize,&BR,NULL)) { free(BaseAddress); CloseHandle(hFile); return -1; } ImageDosHeader = (IMAGE_DOS_HEADER *) BaseAddress; if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { printf("Dos handle invalido"); free(BaseAddress); CloseHandle(hFile); return -1; } ImageNtHeaders = (IMAGE_NT_HEADERS *) (ImageDosHeader->e_lfanew +(DWORD) ImageDosHeader); if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) { printf("Invalid Pe handle"); free(BaseAddress); CloseHandle(hFile); return -1; } ImageSectionHeader = IMAGE_FIRST_SECTION(ImageNtHeaders);
//indirizzo 1 sezione //Verifichiamo se è presente una sezione .aspack printf("La sezione .aspack e' la num :\t"); for(x=0; x <= ImageNtHeaders->FileHeader.NumberOfSections; x++){ if(!strcmp((char*)ImageSectionHeader[x].Name,".aspack")) { aspdir = x; break; } } //Le sezioni da lavare nel dumping sezmen = ImageNtHeaders->FileHeader.NumberOfSections - aspdir; //Vede se ha trovato una sezione .aspack if(aspdir == 0) {printf("Non trovata.\nForse non è packato");return -1;} printf("%X\n",aspdir+1); //calcoliamo Offser e VA della sezione .aspack rawsize = ImageSectionHeader[aspdir].PointerToRawData; VA = ImageNtHeaders->OptionalHeader.ImageBase + ImageSectionHeader[aspdir].VirtualAddress; imagebase = ImageNtHeaders->OptionalHeader.ImageBase; //calcoliamo l’offset e RA dell’OEP e dell’IT OffsetIT = rawsize + it; OffsetOEP = rawsize + oep; addrIT = VA + it; addrOEP = VA + oep; //Calcoliamo la grandezza del file da dumpare size += ImageSectionHeader[0].VirtualAddress; for(x=0; x<=aspdir-1;x++) { size += ImageSectionHeader[x].Misc.VirtualSize; } //chiudiamo tutto xkè abbiamo finito di lavorare con il PE(per il momento) free(BaseAddress); CloseHandle(hFile); //troviamo l’OEP e l’IT pFile = fopen(NomeFile,"rb"); if (pFile==NULL) {printf("Errore ri-apertura file");return 0;} printf("\nInizio ricerca delle info per il decripting:"); printf("\n\tL'OEP originale e’ (RVA):"); fseek(pFile,OffsetOEP,SEEK_SET); oep = getw(pFile); printf(" %X",oep); printf("\n\tL'IT originale e’ (RVA):"); fseek(pFile,OffsetIT,SEEK_SET); it = getw(pFile); printf(" %X",it); fclose(pFile); |
Abbiamo trovato l’Oep e l’it ora dobbiamo fare da debug che ci fermi prima che giocherelli con l’it, x comodità mettiamolo a addrIT
2
//Creamo il processo x il debug if(!CreateProcess(NomeFile,NULL,NULL,NULL,FALSE,DEBUG_ONLY_THIS_PROCESS|CREATE_SUSPENDED,NULL,NULL,&si,&pi)) {printf("\nImp creare il processo\n");return -1;} printf("\nOk processo avviato"); //ci serviranno x varie funzioni HANDLE hProc = pi.hProcess; HANDLE hMainT = pi.hThread; //salviamo il byte prima della modifica, quel addrIt-1 l’ho messo xkè se no c’è esce un eccezione if(!ReadProcessMemory(hProc,(void*)addrIT-1,&buffer,1,NULL)){return -1;} //mettiamo un bp if(!WriteProcessMemory(hProc,(void*)addrIT-1,&int3,1,NULL)){ return -1;} printf("\nBp messo"); // ripristiniamo l'esecuzione ResumeThread(hMainT); //ora inziamo a fare il debug vero e proprio for(;;) { dwContinueStatus = DBG_CONTINUE; WaitForDebugEvent(&DebugEv, INFINITE); // rispondi agli eventi di debug switch (DebugEv.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: if (DebugEv.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { if(DebugEv.u.Exception.ExceptionRecord.ExceptionAddress != (void*)addrIT-1) { dwContinueStatus = DBG_CONTINUE; } else { // risponde al breakpoint printf("\nRaggiunto un bp a: [%8.X]",DebugEv.u.Exception.ExceptionRecord.ExceptionAddress); //rimetto a posto il byte originale if(!WriteProcessMemory(hProc,(void*)addrIT-1,&buffer,1,NULL)){ return -1;} //Ritocca l’eip context.ContextFlags = 0x1003f; GetThreadContext(hMainT,&context); context.Eip--; SetThreadContext(hMainT,&context); //Continua con l’esecuzione ResumeThread(hMainT); |
Ora ci siamo fermata al bp impostato da noi, ora passiamo alla terza parte, cioè il dump
3
//ora cerco di dumpare hFile = CreateFile("MyDump.exe", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile==INVALID_HANDLE_VALUE){return -1;} printf("\nCreato file"); //alloco spazio in memoria BYTE *Section; Section = malloc(size); if(Section == NULL) {CloseHandle(hFile); printf("Errore x buff"); return -1;} //legge in memoria, prendendo l’inizio da leggere e le dimensioni if(ReadProcessMemory(hProc,(void*)imagebase,Section,size,&BR) == FALSE){ printf("\nImpossibile leggere in memoria");free(Section); CloseHandle(hFile); return -1;} //e dumpa if(!WriteFile(hFile,Section,size,&BR,NULL)){printf("\nImpossibile scrivere"); free(Section); CloseHandle(hFile); return -1;}else{printf("\nFile dumpato");} free(Section); CloseHandle(hFile); |
Abbiamo dumpato il tutto, ora dobbiamo modificare il PE del file dumpato:
4
//Apre il file appena creato hFile = CreateFile("MyDump.exe",GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { printf("Non posso aprire il file\n"); return -1; } FileSize = GetFileSize(hFile,NULL); BaseAddress = (BYTE *) malloc(FileSize); if(!ReadFile(hFile,BaseAddress,FileSize,&BR,NULL)) { free(BaseAddress); CloseHandle(hFile); return -1; } ImageDosHeader = (IMAGE_DOS_HEADER *) BaseAddress; if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { printf("Dos handle invalido"); free(BaseAddress); CloseHandle(hFile); return -1; } ImageNtHeaders = (IMAGE_NT_HEADERS *) (ImageDosHeader->e_lfanew +(DWORD) ImageDosHeader); if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) { printf("Invalid Pe handle"); free(BaseAddress); CloseHandle(hFile); return -1; } ImageSectionHeader = IMAGE_FIRST_SECTION(ImageNtHeaders); //modifichiamo l'EP ImageNtHeaders->OptionalHeader.AddressOfEntryPoint = oep; //diminuiamo il munero delle sezioni ImageNtHeaders->FileHeader.NumberOfSections -= sezmen; //Modifichiamo size of image ImageNtHeaders->OptionalHeader.SizeOfImage = size; //riallineo ImageNtHeaders->OptionalHeader.FileAlignment = ImageNtHeaders->OptionalHeader.SectionAlignment; //SizeOfHeader = VA ImageNtHeaders->OptionalHeader.SizeOfHeaders = ImageSectionHeader->VirtualAddress; //RS=VS && RO=VO for(x=0;x<=ImageNtHeaders->FileHeader.NumberOfSections;x++){ ImageSectionHeader[x].SizeOfRawData = ImageSectionHeader[x].Misc.VirtualSize; ImageSectionHeader[x].PointerToRawData = ImageSectionHeader[x].VirtualAddress; } //Modifichiamo l'IT ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = it; //Modifichiamo Base relocation ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0x0000; ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0x0000; //calcoliamo la grandezza dell’it sizIT = 0x7f88; for(x=0;x<=10;x++){ SetFilePointer(hFile,sizIT,NULL,FILE_BEGIN); if(!ReadFile(hFile, &buffer, 4, &BR, NULL)){printf("\nErrore lettura file");return -1;} if(buffer==0){break;} sizeIT+=0x14; sizIT += 0x0c; } //Modifichiamo il size dell'IT, quell +0x14 l’ho aggiunto xkè ho visto ke c’è in tutti i prg :D ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeIT+0x14; //salviamo le modifiche SetFilePointer(hFile,0,NULL,FILE_BEGIN); if(!WriteFile(hFile,BaseAddress,FileSize,&brw,NULL)){ printf("\nErrore nel modificare il Pe");free(BaseAddress); CloseHandle(hFile); return -1;} //se arriviamo qui abbiamo finito; free(BaseAddress); CloseHandle(hFile); dwContinueStatus = DBG_CONTINUE; } } else { // se è eccezione cerca di farlo ripristinare dal prg o esce printf("\nRaggiunta un eccezione a: [%8.X]", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress); dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; } break; case EXIT_PROCESS_DEBUG_EVENT: // Se stiamo qui, significa che il prg sta per chiudersi. printf("\nE'stato chiamato ExitProcess"); ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus); return; break; } ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus); } return 0; } |
Abbiamo finito tutto. Spero che sia abbastanza chiaro, se no rileggete, vedete le reference di ciascuna api, o rileggete i tute sul debug e sul pe. Alla prossima :D
PS: NON LEVATE IL POWERED BY PNLUCK, SENNO VE MAGNO :D
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. Compreso Que che sta mettendo impiedi questo progetto
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.