Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Karman en 18 Julio 2009, 04:09 am



Título: [Source] Crypter Simple Vr 2(?) FIX 1
Publicado por: Karman en 18 Julio 2009, 04:09 am
Bueno, los que me hayan leído mis últimos post verán que arme una clase para desarmar la clásica estructura PE... el tema es que hacía un tiempo había visto el código de un crypter simple en este foro (para ser más exacto http://foro.elhacker.net/programacion_cc/source_crypter_simple-t204227.0.html;msg969905#msg969905 (http://foro.elhacker.net/programacion_cc/source_crypter_simple-t204227.0.html;msg969905#msg969905)) el cual no funcionaba muy bien (con algunos ejecutables el resultado era desastroso) porque no tenía en cuenta un par de cosas que he agregado a este nuevo crypter...

Antes que nada paso a explicar un par de cosas para que a los que le interese el código puedan seguirlo...

1º y fundamental... los tipos de direccionamiento (la parte más complicada...  :P), bueno... en esta clase que cree hay 3 tipos básicos de direccionamiento:
A:Por Offset: la clase lo que hace es subir a memoria el archivo, entonces este tipo de direccionamiento nos lleva directamente a una posición de memoria del archivo, osea suponiendo que nuestra variable que contiene el contenido del archivo se llame buffer:

Citar
Offset(10) => &buffer[10]
*Offset(0) = 'M';*Offset(1) ='Z';

B: Por RVA: la clase es capaz de resolver direcciones virtuales, en este caso al setear un valor, se calculará el offset de acuerdo a este valor y obtendremos la posición de memoria del archivo... por ejemplo:

si una sección empieza físicamente en 400, pero tiene una dirección virtual de 1000, al hacer:

Citar
RVA(1024) = &buffer[424]

sin importar en cual sección se encuentre... (el algoritmo se encarga de eso)
C: por dirección referenciada: esta última opción (que agregué en esta versión) permite obtener el offset real de una dirección (la inversa de Offset), por ejemplo si tenemos una dirección 0x431212 y queremos saber en que punto del archivo se encuentra:

Código:
Address(0x431212) = 325
Offset(325) = 0x431212

bueno, ahora si el código:

Código
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        PE simple crypter (FIX 1)
  3. // Purpose:     Encriptador simple de Ficheros PE
  4. // Author:      Karman
  5. // Created:     2009-10-7
  6. // Copyright:   (c) Exinferis Inc
  7. // Web:         http://www.inexinferis.com.ar
  8. // Vr. : 0.1.1
  9. /////////////////////////////////////////////////////////////////////////////
  10.  
  11. #include <stdio.h>
  12. #include "ExecAnalizer.h"
  13.  
  14. CCHAR DataDirectories[][24]={
  15.  "Export Table",
  16.  "Import Table",
  17.  "Resource Table",
  18.  "Exception Table",
  19.  "Certificate Table",
  20.  "Relocation Table",
  21.  "Debug Table",
  22.  "Architecture Table",
  23.  "Machine Table",
  24.  "Thread Local Storage",
  25.  "Load Config Table",
  26.  "Bound Import Table",
  27.  "Import Address Table",
  28.  "Delay Import Table",
  29.  "COM+ Runtime Header"
  30. };
  31.  
  32. BYTE ourcode[]={
  33.  //push old entrypoint...
  34.  0x68,0x00,0x00,0x00,0x00,
  35.  //push size of code
  36.  0x68,0x00,0x00,0x00,0x00,
  37.  //push address of code
  38.  0x68,0x00,0x00,0x00,0x00,
  39.  //call decrypt
  40.  0xE8,0x00,0x00,0x00,0x00,
  41.  //Ret
  42.  0xc3
  43. };
  44.  
  45. DWORD WINAPI GetFunctionSize(PBYTE dwStart);
  46. VOID  WINAPI descifrar(PBYTE address,INT size, DWORD oep);
  47. VOID  WINAPI cifrar(PBYTE address,INT size);
  48.  
  49. int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPInst,LPSTR lpCmd,int nShow){
  50.  DWORD nImageBase,nEntryPoint;
  51.  PIMAGE_NT_HEADERS pINH;
  52.  PIMAGE_SECTION_HEADER pISHCode;
  53.  PCHAR forig="C:\\WINDOWS\\regedit.exe";
  54.  PCHAR fcrytp="C:\\WINDOWS\\cifrado.exe";
  55.  printf("Abriendo -> %s\n",forig);
  56.  ExecAnalizer crypt(forig);
  57.  //nos aseguramos que sea PE...
  58.  if(crypt.GetDOSHeader()&&crypt.HasNewHeader()&&crypt.IsPE()){
  59.    printf("\tFile Is -> PE\n");
  60.    pINH = crypt.GetNTHeader();
  61.    //datos básicos del ejecutable
  62.    nEntryPoint=pINH->OptionalHeader.AddressOfEntryPoint;
  63.    nImageBase=pINH->OptionalHeader.ImageBase;
  64.    printf("\tEntryPoint -> %X\n",nEntryPoint);
  65.    printf("\tImageBase -> %X\n",nImageBase);
  66.    puts("Buscando Code Section:");
  67.    //sección del código
  68.    pISHCode=crypt.RVA2Section(nEntryPoint);
  69.    if(pISHCode){
  70.      printf("\tCode Section Found At -> %X\n",crypt.Address2Offset((PBYTE)pISHCode));
  71.      DWORD codeStart=pISHCode->VirtualAddress;
  72.      DWORD codeEnd=pISHCode->VirtualAddress+pISHCode->SizeOfRawData;
  73.      printf("\tCode Section Start At -> %X\n",codeStart);
  74.      printf("\tCode Section End At -> %X\n",codeEnd);
  75.      //buscamos si alguna otra cosa se encuentra tb en el area de código
  76.      puts("Buscando Tablas en Code Section (Calculando tamaño real del código)");
  77.      for(int i=0;i<15;i++){
  78.        if(pISHCode==crypt.RVA2Section(pINH->OptionalHeader.DataDirectory[i].VirtualAddress)){
  79.          printf("\t%s is in Code Section At %X - %X\n",DataDirectories[i],
  80.            pINH->OptionalHeader.DataDirectory[i].VirtualAddress,
  81.            pINH->OptionalHeader.DataDirectory[i].Size
  82.          );
  83.          DWORD tAdress=pINH->OptionalHeader.DataDirectory[i].VirtualAddress;
  84.          DWORD tSize=(pINH->OptionalHeader.DataDirectory[i].VirtualAddress+pINH->OptionalHeader.DataDirectory[i].Size);
  85.          if(nEntryPoint<tAdress){
  86.            if(codeEnd>tAdress)
  87.              codeEnd=tAdress;
  88.          }else{
  89.            if(codeStart<tSize)
  90.              codeStart=tSize;
  91.          }
  92.        }
  93.      }
  94.      puts("Tamaño real del código:");
  95.      printf("\tCode Section Start At -> %X\n",codeStart);
  96.      printf("\tCode Section End At -> %X\n",codeEnd);
  97.      // Valores reales (en el archivo)
  98.      DWORD rCodeStart=(DWORD)crypt.RVA2Offset(codeStart);
  99.      DWORD rCodeEnd=(DWORD)crypt.RVA2Offset(codeEnd);
  100.      //buscamos espacio libre dentro de la sección code para copiarnos...
  101.      puts("Buscando Espacio para nuestro Código:");
  102.      //tamaño de nuestro código...
  103.      DWORD decrypcodefuncsize=GetFunctionSize((PBYTE)descifrar);
  104.      DWORD decrypcodesize=decrypcodefuncsize+0x20;
  105.      //Espacios libres???
  106.      DWORD dwBlanks=0,dwAddress=(pISHCode->PointerToRawData+pISHCode->SizeOfRawData);
  107.      for(;((dwAddress>rCodeEnd)&&(dwBlanks<decrypcodesize));dwAddress--)
  108.        if(!*crypt.OffsetValue(dwAddress))dwBlanks++;else dwBlanks=0;
  109.      //tiene espacio???
  110.      printf("\tEspacio Necesario: %X - Espacio encontrado: %X\n",decrypcodesize,dwBlanks);
  111.      if(decrypcodesize>=dwBlanks){
  112.        printf("\tFree Space At -> %X\n",dwAddress);
  113.        //ciframos...
  114.        cifrar((PBYTE)crypt.RVAValue(codeStart),codeEnd-codeStart);
  115.        //copiamos la función que descifra
  116.        memcpy((PVOID)crypt.OffsetValue(dwAddress),(PVOID)descifrar,decrypcodefuncsize);
  117.        //armamos cabecera...
  118.        *(DWORD *)&ourcode[0x01]=nEntryPoint+nImageBase;
  119.        *(DWORD *)&ourcode[0x06]=codeEnd-codeStart;
  120.        *(DWORD *)&ourcode[0x0B]=codeStart+nImageBase;
  121.        *(DWORD *)&ourcode[0x10]=-(decrypcodefuncsize+20);
  122.        dwAddress+=decrypcodefuncsize;
  123.        memcpy((PVOID)crypt.OffsetValue(dwAddress),(PVOID)ourcode,24);
  124.        //calculamos nuevo entrypoint
  125.        pINH->OptionalHeader.AddressOfEntryPoint=crypt.Offset2RVA(dwAddress);
  126.        // Damos permiso de escritura a la sección. Si no hacemos esto nos dara error.
  127.        pISHCode->Characteristics |= IMAGE_SCN_MEM_WRITE;
  128.        // Corregimos tamaño de la sección virtual si insuficiente
  129.        if(pISHCode->Misc.VirtualSize<(crypt.Offset2RVA(dwAddress)-pISHCode->VirtualAddress+24))
  130.          pISHCode->Misc.VirtualSize=(crypt.Offset2RVA(dwAddress)-pISHCode->VirtualAddress+24);
  131.        crypt.Save(fcrytp);
  132.      }else
  133.        puts("\tSin espacio Suficiente... :(");
  134.    }
  135.  
  136.    system("pause");
  137.  }
  138. }
  139.  
  140. DWORD WINAPI GetFunctionSize(PBYTE dwStart){
  141.  PBYTE dwEnd=dwStart;
  142. while(*dwEnd!=0xC3&&*dwEnd!=0xC2)dwEnd++;
  143. if(*dwEnd==0xC2)return (dwEnd-dwStart+3);
  144. return (dwEnd-dwStart+1);
  145. }
  146.  
  147. VOID  WINAPI descifrar(PBYTE address,INT size, DWORD oep){
  148.  while(size>0){
  149.    *(address++)^=0x65;
  150.    size--;
  151.  }
  152.  //set ret to old entry point
  153.  asm("mov %0 , 0x04(%%esp)"::"r"(oep));
  154. }
  155.  
  156. VOID  WINAPI cifrar(PBYTE address,INT size){
  157.  while(size>0){
  158.    *(address++)^=0x65;
  159.    size--;
  160.  }
  161. }

Detalles a destacar a diferencia de la primera versión del cripter:
1º Checkeo "de qué se cifra": el código no cifra toda la sección CODE, ya que muchos compiladores tienen la opción de combinar dentro de la sección CODE otras estructuras (IMPORT por ejemplo), y al cifrar esta estructura el programa ya no es válido (el cifrado de la IAT va más allá de este simple código, además de que desconozco como realmente se hace)...

2º Corrección de secciones: nuevamente el código anterior agregaba su código dentro de la sección CODE, pero no verificaba que esta modificación esté dentro de los valores definidos en la sección...

3º El código para descifrar mantiene cierta "lógica" secuencial, (aunque no logré hacer funcionar el código original) cuando lo intentaba debuggear los debuggers no lo entendían...

bue... eso es todo...  :P ...

S2

PD: me olvidaba de poner la dir del code:

Crypter Simple (http://www.inexinferis.com.ar/files/PECrypt.rar)

PD2: Desconozco si el código tenga algún problema... con los ejecutables que probé funcionó...  :P


Título: Re: [Source] Crypter Simple Vr 2(?) FIX 1
Publicado por: Maurice_Lupin en 16 Febrero 2012, 22:50 pm
el link de descarga no funciona si puedes ponerlo en mediafire, gracias.
Me parece un buen tema para no tener ni un comentario.

Saludos