GabriPr0 Packer Alpha Version!

Stato
Discussione chiusa ad ulteriori risposte.

GabriPr0

Utente Electrum
25 Aprile 2009
303
13
32
132
Ultima modifica da un moderatore:
Dal titolo sembra chissa che cosa... ma è un semplice packer che verifica se all'apertura del programma è presente un Debbugger. In caso positivo continua con un eccezione.
E' possibile packare un programma trascinandolo sul Packer o aprendo il programma e inserendo il nome del file.
Oltre al programma verrà scritto un file di Log contenente le informazioni principali come i byte liberi.
Il packer è stato testato con programmi compilati con

  • Dev-C++
  • Borland Dephi 4.0
  • Visual Studio 8 (in alcuni casi)

E' in fase di sviluppo una versione totalmente compatibile con

  • Visual Studio 8
  • Visual Basic 6.0
  • Borland C++ for Win32

Per questi motivi sto cercando qualcuno che mi dia una mano ( oltre a retr0 che non è mai on su MSN!)
Essendo un progetto Open Suorce ho optato per iniziare con la licenza GPL.

Bug Conosciuti
Codice:
1. Il packer non controlla quanti sono i byte liberi tra le sezioni (anche se 18 byte ci sono sempre)
2. Funziona solo su alcuni programmi
3. Se viene attaccato il processo, quando il programma è già aperto, il debugger non viene detectato.

DOWNLOAD

Link Diretto

MultiUpload


SCREEN
Programma:
Packer.jpg

Eccezione di Olly
Eccezione.jpg


SUORCE

Download

Il suorce è commentato e comprensibile. So che è scritto un po' male.. e soprattutto indentato male.
Ci sono dei commenti sulle prossime funzioni del programma e delle cose da correggere.

PHP:
/*  
    
    GabriPr0 Packer Alpha Version!
    With this program you can "pack" your own .exe file.
    This packer may not work with all exe files.
    I decline any responsability if you damage your program.

    Copyright (C) 2010  Gabriele Serra ( GabriPr0 )

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.


*/
#include <windows.h>
#include <iostream>
#include <fstream> 

using namespace std;

//Le tre strutture di cui avrò bisogno:
//l'header delle sezioni, le varie caratteristiche (come entrypoint o imagebase) e il DOS header.
//Per un corretto approccio a questo suorce consiglio di studiare un guida sul formato PE
IMAGE_SECTION_HEADER *ImageSectionHeader;
IMAGE_NT_HEADERS *ImageNtHeaders;
IMAGE_DOS_HEADER *ImageDosHeader;

DWORD VaPartenza = 0;
DWORD FileOffset;
//Inizializzo a 0 perchè ne avrò bisogno.. capirete dopo!
BYTE Op[] = { 0x00 , 0x00 , 0x00 , 0x00 };
//La variabile VA conterrà il valore da sotrarre (insieme all'imagebase) al VA per ottenere il FileOffset
DWORD VA;
//Funzione per calcolare i byte di una funzione CALL
void CalcoloCode(DWORD VAPartenza , DWORD VADestinazione);
//Bè il nome della funz dice già tutto!
bool FileExist(LPSTR Filename); 
//Per chi non ricordassi argc = numero argomenti , argv = i vari argomenti
int main(int argc, char* argv[]) 
 
{   
    cout << "GabriPr0 Packer Alpha Version." << endl;
    cout << "This is an Open Suorce project!" << endl;
    //Stream per scrivere su un file, in questo caso Log.txt
    ofstream* Log;
    //Se non esiste   
    if(!FileExist("Log.txt"))
    {
    
    Log = new ofstream("Log.txt");
    //Verrà creato
    cout << "Log File don't exist... it will be create now!" << endl;
    
    } else {
    //altrimenti lo apre in moalità append
    Log = new ofstream("Log.txt" , ios::app);
    //e scrive un barra di separazione
    *Log << "---------------------------------------" << endl;
    
    }
    
    if(!Log){cout << "Unable to Create Log file!" << endl;}    
    
    HANDLE HandleFile;
    
    //Max Path = 260 ..
    char Filename[MAX_PATH];
    
    //Se gli argomenti passati al cmd sono diversi da 2
    if(argc != 2) {
    
    //Inserisci il nome file da input
    cout << "Insert file name..." << endl;
           
    cin >> Filename;
    
    //Ottengo l'handle del file
    HandleFile = CreateFile(Filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0 ,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);  
    
    cout << "Scanning... \nPacking " << Filename << endl;
    *Log << "Packing: " << Filename << endl;  
               
    } else {
    //altrimenti usa il secondo argomento passato al cmd come nome file
    //(il primo argomento è il programma stesso)              
    HandleFile = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0 ,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);  
    cout << "Scanning... \nPacking " << argv[1] << endl;
    *Log << "Packing: " << argv[1] << endl; 
             
    }
    
    //Errore impossibile aprire il file    
    if (HandleFile == INVALID_HANDLE_VALUE ) 
    { 
        cout << "Error: Unable to open File" << endl;
        cin.get();
        return -1; 
    }
    
    //Crea una mappatura del file
    HANDLE MpObj = CreateFileMapping(HandleFile, NULL, PAGE_READONLY, 0, 0, 0);
    
    //Errore: Impossibile Mappare il file
    if (!MpObj)
    {
                 
    CloseHandle(HandleFile);
    cout << "Unable to create MapFile" << endl;
    cin.get();
    return -1;
    
    }
    
    //Mappa il file e restituisce l'address dell'inizio della mappatura
    DWORD BaseAddress = (DWORD)MapViewOfFile(MpObj, FILE_MAP_READ, 0, 0, 0);
    
    //se BaseAddress = 0 Errore: Impossibile...
    if (!BaseAddress)
    {
    
    CloseHandle(HandleFile);
    CloseHandle(MpObj);
    cout << "Unable to view mapping file" << endl;
    cin.get();
    return -1;
    
    }
    
    *Log << hex << "Base Address of Mapping Object: " << BaseAddress << endl;
    
    //Per utilizzare la struttura DosHeader basta farla puntare al BaseAddress del file mappato     
    ImageDosHeader = (IMAGE_DOS_HEADER*)BaseAddress;
    
    //Se e_magic (i primi 2 byte in poche parole) diversi da IMAGE_DOS_SIGNATURE ( MZ [ 4D , 5A ] )
    //Errore: Dos Header invalido.. non è un eseguibile!
    if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    
    {
   
    cout << "Invalid DOS Header" << endl;
    CloseHandle(HandleFile);
    CloseHandle(MpObj);
    cin.get();
    return -1;

    } 
    
    //Per riempire la struttura NtHeaders basta farla puntare all'inizio del PE + e_lfanew
    ImageNtHeaders = (IMAGE_NT_HEADERS *)(ImageDosHeader->e_lfanew +(DWORD)ImageDosHeader);
    
    //Se i primi due byte della struttura dopo il DosHeader diversi da IMAGE_NT_SIGNATURE (PE [ 50 , 45 , 00 , 00 ] )
    //Errore: il file che stiamo "esaminando" non è un PE!
    if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE)     
    
    {
                                  
    cout << "Invalid PE Format" << endl;
    CloseHandle(HandleFile);
    CloseHandle(MpObj);
    cin.get();
    return -1;
    
    }           
    
    //Ottengo l'imagebase ( o baseaddress) del PE che sto packando       
    DWORD ImageBase = ImageNtHeaders->OptionalHeader.ImageBase;
    
    *Log << "Base Address of file: " << ImageBase << endl;
    
    //Riempo la struttura section header grazie alla macro fornita da winnt.h
    ImageSectionHeader = IMAGE_FIRST_SECTION(ImageNtHeaders);
 
    //Per ogni sezione del file
    for (int x = 0; x < ImageNtHeaders->FileHeader.NumberOfSections; x++)
 
    {
    
    //trova i byte liberi in fondo alla sezione 
    DWORD BaseByte = ImageSectionHeader[x].Misc.VirtualSize + ImageSectionHeader[x].PointerToRawData;
     
     //Correggere
     if ( BaseByte > 0 ){
    
    /*      
    DWORD LOL = SetFilePointer(HandleFile, BaseByte, NULL, FILE_BEGIN);
    
    if(LOL == INVALID_SET_FILE_POINTER)
    {
      cout << "Error: Unable to Set File Pointer" << endl;
      CloseHandle(HandleFile);
      CloseHandle(MpObj);
      cin.get();
      return -1 ;
    }
     
          
     BYTE NumeroByteNecessari[17];
     DWORD nByteRead;
     BOOL Read = ReadFile(HandleFile , NumeroByteNecessari , sizeof(NumeroByteNecessari) , &nByteRead , NULL);
     if(!Read)
     {
              cout << "Error: Unable to Read Byte!" << endl;
     }
     Read = FALSE;
     for(int Loop = 0; Loop < sizeof(NumeroByteNecessari); Loop++){
            if(NumeroByteNecessari[x] != 0x00)
            {
            Read = TRUE;
            }
    }
    if(Read)
    {
            cout << "I Byte nn sono liberi!" << endl;
            cin.get();
            return 0;
    }
            
            if(!RvaPartenza)
            {
                            
            VA = ImageSectionHeader[x].VirtualAddress - ImageSectionHeader[x].PointerToRawData;
            //Forse inutile magari Log
            cout << "BaseByte " << BaseByte << " VA " << VA << " Imagebase " << ImageBase << endl;
            RvaPartenza = BaseByte + VA + ImageBase;
            FileOffset = BaseByte; 
           
           }     
           
     
     */
     //Per ora lascio così
     if(!VaPartenza){
                   
     VA = ImageSectionHeader[x].VirtualAddress - ImageSectionHeader[x].PointerToRawData;
     VaPartenza = BaseByte + VA + ImageBase;
     FileOffset = BaseByte;         
     
     }               
     
     *Log << "Free Byte, Starting at Offset: " << BaseByte << endl;
           
     }else{
 
      cout << "Error!" << endl;
      CloseHandle(HandleFile);
      CloseHandle(MpObj);
      cin.get();
      return -1 ;
 
    }//fine if
 
    } //Fine for
        
    cout << "End Scanning: Calculating Code and Write!" << endl;
    
    //Sposto il FilePointer al FileOffset dei byte liberi
    DWORD Ris = SetFilePointer(HandleFile, FileOffset, NULL, FILE_BEGIN);
    
    //Se ris = INVALID_SET_FILE_POINTER allora
    //Errore: Impossibile spostare il file pointer
    if(Ris == INVALID_SET_FILE_POINTER)
    {
      cout << "Error: Unable to Set File Pointer" << endl;
      CloseHandle(HandleFile);
      CloseHandle(MpObj);
      cin.get();
      return -1 ;
    }
    
    //Dichiaro i Byte del packer
    //copiati da Kernel32 o.O
    //64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
    //8B40 30        MOV EAX,DWORD PTR DS:[EAX+30]
    //0FB640 02      MOVZX EAX,BYTE PTR DS:[EAX+2]
    //85C0           TEST EAX,EAX
    //75 01          JNZ SHORT "ADDRESS SOTTO RETN" OVVERO ECCEZIONE
    //C3             RETN
    BYTE IsDbgPresent[] = { 0x64 , 0xA1 , 0x18 , 0x00 , 0x00 , 0x00 , 0x8B , 0x40 , 0x30 , 0x0F ,0xB6 , 0x40, 0x02 , 0x85 , 0xC0 , 0x75 , 0x01 , 0xC3};
    
    //Scrivo i byte sul File..       
    DWORD lpNumberOfBytesWritten;
    if(!WriteFile(HandleFile, IsDbgPresent, sizeof(IsDbgPresent), &lpNumberOfBytesWritten, NULL))
    {
           //Se ritorna 0 ( FALSE ) allora:                  
           cout << "Error: Unable to write file" << endl;
           CloseHandle(HandleFile);
           CloseHandle(MpObj);
           cin.get();
           return -1;
                     
     }
    
    //Ottengo l'entrypoint del file
    DWORD RvaEntryPoint = ImageNtHeaders->OptionalHeader.AddressOfEntryPoint;
       
    //Calcolo i byte da scrivere per la Call che parte dal VA dell'entrypoint + 1 (lascio il PUSH EBP che avvolte genera errore se lo levo )
    // e che ha come destinazione il VA dei byte che ho scritto prima
    CalcoloCode(RvaEntryPoint+ImageBase+1 , VaPartenza);
       
    //Sposto il file pointer alla seconda istruzione del programma
    Ris = SetFilePointer(HandleFile, RvaEntryPoint - VA +1, NULL, FILE_BEGIN);
    
    //se Ris = INVALID_SET_FILE_POINTER
    //allora Errore..
    if(Ris == INVALID_SET_FILE_POINTER)
    {
      cout << "Error: Unable to Set File Pointer" << endl;
      CloseHandle(HandleFile);
      CloseHandle(MpObj);
      cin.get();
      return -1 ;
    }    
    
    //Scrivo i Byte che compongono la CALL
    if(!WriteFile(HandleFile, Op, sizeof(Op) + 1, &lpNumberOfBytesWritten, NULL))
    {
           //e se ritorna 0 errore:                  
           cout << "Error: Unable to write file" << endl;
           CloseHandle(HandleFile);
           CloseHandle(MpObj);
           cin.get();
           return -1;
                     
    }
    
    //Tutto è andato bene, il file è stato packato con successo!        
    cout << "File Succesfully Packed!" << endl;             
    *Log << "File Succesfully Packed!" << endl; 
     
     CloseHandle(HandleFile);
     CloseHandle(MpObj);  
     system("pause");
     //cancello il puntatore allo stream
     delete Log;
     return 0;  
}                        
//Funzione per calcolare i byte che compongono un istruzione CALL
void CalcoloCode(DWORD VAPartenza , DWORD VADestinazione){
           
    //Destinazione CALL - Partenza CALL - 5 (ovvero i byte che compongono la call)   
    VADestinazione = VADestinazione - VAPartenza -5;      
    
    
    //Conversione Big Endian -> Little Endian
    //inverto i byte dato i processori Intel usano questa "notazione"
    //nelle CALL e nei JMP infatti il byte più significativo è l'ultimo e quello meno
    //il primo.
    //Se ad esempio il risultato della sottrazione è 00006765 la call sarà
    //E8 65670000 .. per questo ho inizializzato a 0 l'array!
    unsigned char *ptr = (unsigned char *)&VADestinazione;
    
    //il primo byte è E8 CALL
    Op[0] = 0xE8;   
    Op[1] = ptr[0];
    Op[2] = ptr[1];
    Op[3] = ptr[2];
    Op[4] = ptr[3];    
        
    return;
}
//Funzione per accertare se un file esiste..
bool FileExist(LPSTR Filename){
     //apro il file Filename con permesso di lettura
     FILE* File = fopen(Filename , "r");
     //se File è nonzero esiste
     if (File)
    {
        //chiudo e ritorno True
        fclose(File);
        return true;
    }
    //altrimenti ritorno false
    return false;
}
Crediti

  • Il mio grande amico retr0bot per la base (il suorce del codicecavo :D ) e che mi deve dare una mano su MSN
  • D4n13le che mi sopporta su skype e mi ha risolto il problema della conversione Big -> Little endian
 
stavo facendo delle prove per VB 6 ma devo calcolare tipo 3 o 4 call... vedo se riesco a risolvere diversamente
 
Nice, ma per detectare un debugger potresti iniettare un codice che controlli che il debugger c'è ogni tot di sec opppure di continuo, ma mi sembra troppo difficile da realizzare in un linguaggio del genere (while 1==1, uhuh asd lol)...
 
ahahahah hai ragione fabio ahahaha sono convinti che la parola debugger significhi togliere bug ahahahahaha nabboniiiiiiiiiiii imparate a programmare xD ciao a dopo fabio
 
Stato
Discussione chiusa ad ulteriori risposte.