Aspack 2.12 automatic unpacking

Data

by "Pnluck"

 

29/10/2004

UIC's Home Page

Published by Quequero


Ke bello riempire gli spazi vuoti

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ò :

  1. Prendere l’image-base e il VirtualAddress della sezione .aspack (se è presente) e salvarli in variabili, e trovare l’IT e l’OEP.
  2. Creare un debug ad hoc,che ci fermi prima che aspack giocherelli con l’IAT
  3. Abbena ci fermiamo, cioè incontriamo un bp, dobbiamo dumpare tutte le sezione tranne quelle da .aspack in poi
  4. Aprire il file dumpato e cambiare il numero di sezioni, il file-allignament, l’OEP e L’it e quello che si faceva quando si usava PEdito cioè RS=VS && RO=VO, e dobbiamo azzerare il campo Relocation e calcolare la grandezza dell’IT.

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 del file

    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 del PE

        //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.