GUIDA Crackme #6: Password Keeper (API Obfuscation, VirtualProtect)

Pubblicità

DispatchCode

Moderatore
Staff Forum
Utente Èlite
Messaggi
2,329
Reazioni
1,927
Punteggio
134

Crackme #6, Password Keeper​

Autore crackme: n30np14gu3


0 - Introduzione​

Questo crackme rientra sicuramente tra i più interessanti tra quelli presentati qui. Non è stato semplice a prima vista, specie perchè ho dovuto interrompere il debug per diversi giorni... e quando ci ho rimesso mano, non ricordavo nulla (la prima esplorazione non prevedeva raccolta di informazioni; è stata una pessima scelta).
Se siete interessati ad altro materiale di questo tipo, potete consultare le Guide degli gli utenti.

In questo crackme ci sono alcune cose davvero interessanti (VirtualProtect, API Obfuscation), quindi vi suggerirei di proseguire con la lettura. ? Tecniche come queste (in particolare quella che riguarda le API) vengono utilizzate sia per la protezione del software, sia per lo scopo contrario (malware), seppur meno avanzate di altre (virtual machine, in testa).

1 - Analisi statica​

Come sempre per prima cosa mi avvalgo di due strumenti, per dare un'occhiata al file EXE: RDG Packer Detector e CF Explorer.
RDG Packer Detector segnala un possibile "isDebuggerPresent()" ma non riporta informazioni sulle compressioni, non rileva nulla:

1.png

Guardando la import directory ci sono alcune librerie, e si nota in effetti KERNEL32.DLL, dove si può notare isDebuggerPresent:

2.png

Ho deciso di effettuare un altro controllo, utilizzando un'utility di cui non mi sembra di aver mai accennato nei precedenti articoli. Si chiama strings, e lo trovate su Sysinternals. In poche parole riporta tutte le stringhe (sequenze di ASCII/Unicode) presenti nell'eseguibile.
Questo un output del programma lanciandolo senza argomenti:

Codice:
Strings v2.54 - Search for ANSI and Unicode strings in binary images.
Copyright (C) 1999-2021 Mark Russinovich
Sysinternals - www.sysinternals.com

usage: strings [-a] [-f offset] [-b bytes] [-n length] [-o] [-s] [-u] <file or directory>
-a     Ascii-only search (Unicode and Ascii is default)
-b     Bytes of file to scan
-f     File offset at which to start scanning.
-o     Print offset in file string was located
-n     Minimum string length (default is 3)
-s     Recurse subdirectories
-u     Unicode-only search (Unicode and Ascii is default)
-nobanner
       Do not display the startup banner and copyright message.

evito di riportare l'intero output, mi limito alle poche stringhe interessanti che si possono vedere:
Codice:
string too long
please, check passwords.db file
Welcome to Super Password Keeper
Enter password for decryption->
pause

Non è un buon segno, in quanto non sono presenti messaggi di "ok" o "fallimento", di conseguenza è altamente probabile che le stringhe non siano in chiaro.
La cartella che contiene l'eseguibile ha al suo interno un altro file, chiamato "passwords.db", il cui contenuto risulta praticamente non leggibile.

2 - Prima Esecuzione​

Lanciando l'eseguibile e inserendo una password a caso, ottengo questo output:

3.png

Qui inizio a capire che la cosa sarà interessante...
Il messaggio ricevuto è una stringa non presente in chiaro nell'exe, e la finestra che si vede è una MessageBox, che tuttavia non risulta tra le funzioni importate. A questo punto è ora di aprire il debugger...

3 - Analisi dinamica (con x32dbg)​

Sapendo che ci sono stringhe in chiaro e che si tratta di un messaggio di benvenuto, cerco quelle, così da raggiungere subito quella procedura e settare un breakpoint (bp). Già le istruzioni sopra a questi messaggi si rivelano interessanti, come potete vedere dallo screen sottostante:

4.png

NOTA: ho già settato alcuni bp, l'articolo e gli screen li sto facendo successivamente a seguito della risoluzione (non sono mai sicuro di arrivare al termine ?).

Ho già visto cose di quel tipo, di solito si tratta di un modo per "nascondere" le stringhe nell'eseguibile. Risalgo la procedura sino all'entry point della stessa e vedo che le cose... migliorano... guardate l'immagine sottostante:
5.png

le prime istruzioni sulle quali mi cade l'occhio sono:

Codice:
003D20DB | 64:A1 30000000              | mov eax,dword ptr fs:[30]                    |
003D20E1 | 8B40 0C                     | mov eax,dword ptr ds:[eax+C]                 |
003D20E4 | 8B40 0C                     | mov eax,dword ptr ds:[eax+C]                 |
003D20E7 | 8B70 18                     | mov esi,dword ptr ds:[eax+18]                |

siamo in x86, quindi il registro FS punta a una struttura dati chiamata TEB (Thread Environment Block), che contiene tutte le info sul Thread in esecuzione. L'offset 0x30 contiene un puntatore a un'altra struttura, PEB (Process Environment Block). Anche questa sequenza di istruzioni mi fa già capire cosa accade, ma ho la certezza controllando gli offset che vengono sommati.

Su MSDN potete trovare tutte le info, io riporto solo la struttura:

C:
typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  PVOID                         Reserved4[3];
  PVOID                         AtlThunkSListPtr;
  PVOID                         Reserved5;
  ULONG                         Reserved6;
  PVOID                         Reserved7;
  ULONG                         Reserved8;
  ULONG                         AtlThunkSListPtr32;
  PVOID                         Reserved9[45];
  BYTE                          Reserved10[96];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved11[128];
  PVOID                         Reserved12[1];
  ULONG                         SessionId;
} PEB, *PPEB;

se contate 0xC (12d) bytes, arrivate al membro chiamato Ldr, che è di tipo PPEB_LDR_DATA:
C:
typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];
  PVOID      Reserved2[3];
  LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

ecco, viene selezionato InMemoryOrderModuleList. Dal nome avrete già intuito magari di cosa si tratta: in poche parole è una linked list dove ogni elemento contiene info su una DLL.
Tutto il codice che segue e che riporto anche qui per chiarezza, non è altro che un loop; vengono utilizzati alcuni "ordinal" (è un identificativo numerico che consente di individuare una specifica funzione, trovate tute le info guardando il PE Header; in questo caso in realtà è probabile sia un checksum, non mi sembra in chiaro).

Codice:
003D2101 | 3BCE                        | cmp ecx,esi                                  | ecx:"LoadLibraryExA"
003D2103 | 74 4F                       | je passwordkeeper.3D2154                     |
003D2105 | 8B79 18                     | mov edi,dword ptr ds:[ecx+18]                | ecx+18:"ryExW"
003D2108 | 85FF                        | test edi,edi                                 |
003D210A | 74 48                       | je passwordkeeper.3D2154                     |
003D210C | 8B49 20                     | mov ecx,dword ptr ds:[ecx+20]                | ecx:"LoadLibraryExA", ecx+20:"adLibraryW"
003D210F | 8D1CB9                      | lea ebx,dword ptr ds:[ecx+edi*4]             | ebx:"ÕË\t", ecx+edi*4:"Exception"
003D2112 | 03DE                        | add ebx,esi                                  | ebx:"ÕË\t"
003D2114 | 8B4B FC                     | mov ecx,dword ptr ds:[ebx-4]                 | ecx:"LoadLibraryExA", ebx-4:"–Ë\t"
003D2117 | 8D5B FC                     | lea ebx,dword ptr ds:[ebx-4]                 | ebx:"ÕË\t", ebx-4:"–Ë\t"
003D211A | 03CE                        | add ecx,esi                                  | ecx:"LoadLibraryExA"
003D211C | 4F                          | dec edi                                      |
003D211D | BE C59D1C81                 | mov esi,811C9DC5                             |
003D2122 | 8A11                        | mov dl,byte ptr ds:[ecx]                     | ecx:"LoadLibraryExA"
003D2124 | 41                          | inc ecx                                      | ecx:"LoadLibraryExA"
003D2125 | 84D2                        | test dl,dl                                   |
003D2127 | 74 24                       | je passwordkeeper.3D214D                     |
003D2129 | 0F1F80 00000000             | nop dword ptr ds:[eax],eax                   |
003D2130 | 0FBED2                      | movsx edx,dl                                 |
003D2133 | 8D49 01                     | lea ecx,dword ptr ds:[ecx+1]                 | ecx:"LoadLibraryExA", ecx+1:"oadLibraryExA"
003D2136 | 33D6                        | xor edx,esi                                  |
003D2138 | 69F2 93010001               | imul esi,edx,1000193                         |
003D213E | 8A51 FF                     | mov dl,byte ptr ds:[ecx-1]                   |
003D2141 | 84D2                        | test dl,dl                                   |
003D2143 | 75 EB                       | jne passwordkeeper.3D2130                    |
003D2145 | 81FE 0F07B253               | cmp esi,53B2070F                             |
003D214B | 74 0B                       | je passwordkeeper.3D2158                     |
003D214D | 8B70 18                     | mov esi,dword ptr ds:[eax+18]                |
003D2150 | 85FF                        | test edi,edi                                 |
003D2152 | 75 C0                       | jne passwordkeeper.3D2114                    |
003D2154 | 8B00                        | mov eax,dword ptr ds:[eax]                   | eax:&"¸:í", [eax]:&"ˆ”í"
003D2156 | EB 8F                       | jmp passwordkeeper.3D20E7                    |
003D2158 | 8B45 C0                     | mov eax,dword ptr ss:[ebp-40]                |

per capire di che funzione si tratta, ho settato un bp all'ultima istruzione che vedete qui sopra, e come notate dai commenti, quando l'esecuziione si blocca al bp, si vede che si tratta di LoadLibrary (già dal nome si intuisce l'utilizzo: infatti carica una specifica libreria che viene passata come parametro).
Qualche istruzione sotto e ci ritroviamo di fronte a quanto ho mostrato nello screen sopra:

Codice:
003D2171 | 74 67                       | je passwordkeeper.3D21DA                     |
003D2173 | C645 E4 45                  | mov byte ptr ss:[ebp-1C],45                  | 45:'E'
003D2177 | B0 30                       | mov al,30                                    | 30:'0'
003D2179 | 3245 E4                     | xor al,byte ptr ss:[ebp-1C]                  |
003D217C | B1 36                       | mov cl,36                                    | 36:'6'
003D217E | 324D E4                     | xor cl,byte ptr ss:[ebp-1C]                  |
003D2181 | B4 76                       | mov ah,76                                    | 76:'v'
003D2183 | 8845 E5                     | mov byte ptr ss:[ebp-1B],al                  |
003D2186 | B2 20                       | mov dl,20                                    | 20:' '
003D2188 | 884D E6                     | mov byte ptr ss:[ebp-1A],cl                  |
003D218B | B5 77                       | mov ch,77                                    | 77:'w'
003D218D | 8A4D E4                     | mov cl,byte ptr ss:[ebp-1C]                  |
003D2190 | B6 6B                       | mov dh,6B                                    | 6B:'k'
003D2192 | C645 CB 29                  | mov byte ptr ss:[ebp-35],29                  | 29:')'
003D2196 | 32E1                        | xor ah,cl                                    |
003D2198 | 8A45 CB                     | mov al,byte ptr ss:[ebp-35]                  |
003D219B | B3 37                       | mov bl,37                                    | 37:'7'
003D219D | 32C1                        | xor al,cl                                    |
003D219F | C645 CA 29                  | mov byte ptr ss:[ebp-36],29                  | 29:')'
003D21A3 | 8845 ED                     | mov byte ptr ss:[ebp-13],al                  |
003D21A6 | B7 21                       | mov bh,21                                    | 21:'!'
003D21A8 | 8A45 CA                     | mov al,byte ptr ss:[ebp-36]                  |
003D21AB | 32D1                        | xor dl,cl                                    |
003D21AD | 32C1                        | xor al,cl                                    |
003D21AF | 8865 E9                     | mov byte ptr ss:[ebp-17],ah                  |
003D21B2 | 8845 EE                     | mov byte ptr ss:[ebp-12],al                  |
003D21B5 | 32D9                        | xor bl,cl                                    |
003D21B7 | 8D45 E5                     | lea eax,dword ptr ss:[ebp-1B]                |
003D21BA | C645 EF 00                  | mov byte ptr ss:[ebp-11],0                   |
003D21BE | 32E9                        | xor ch,cl                                    |
003D21C0 | 8855 E7                     | mov byte ptr ss:[ebp-19],dl                  |
003D21C3 | 32F1                        | xor dh,cl                                    |
003D21C5 | 885D E8                     | mov byte ptr ss:[ebp-18],bl                  |
003D21C8 | 32F9                        | xor bh,cl                                    |
003D21CA | 886D EA                     | mov byte ptr ss:[ebp-16],ch                  |
003D21CD | 50                          | push eax                                     |
003D21CE | 8875 EB                     | mov byte ptr ss:[ebp-15],dh                  |
003D21D1 | 887D EC                     | mov byte ptr ss:[ebp-14],bh                  |
003D21D4 | C645 EF 00                  | mov byte ptr ss:[ebp-11],0                   |
003D21D8 | FFD6                        | call esi                                     |
003D21DA | E8 B1FBFFFF                 | call passwordkeeper.3D1D90                   |
003D21DF | 8B0D 50403D00               | mov ecx,dword ptr ds:[<&?cout@std@@3V?$basic | 003D4050:&"`0år"
003D21E5 | 68 20253D00                 | push passwordkeeper.3D2520                   |
003D21EA | 84C0                        | test al,al                                   |
003D21EC | 75 17                       | jne passwordkeeper.3D2205                    |
003D21EE | BA F0413D00                 | mov edx,passwordkeeper.3D41F0                | 3D41F0:"please, check passwords.db file"
003D21F3 | E8 E8000000                 | call passwordkeeper.3D22E0                   |
003D21F8 | 8BC8                        | mov ecx,eax                                  |
003D21FA | FF15 48403D00               | call dword ptr ds:[<&??5?$basic_istream@DU?$ |
003D2200 | E9 B2000000                 | jmp passwordkeeper.3D22B7                    |
003D2205 | BA 10423D00                 | mov edx,passwordkeeper.3D4210                | 3D4210:"Welcome to Super Password Keeper"
003D220A | E8 D1000000                 | call passwordkeeper.3D22E0                   |

anche qui, per evitare di capire e farmi i calcoli "a mano" ho settato un bp all'indirizzo 0x003D21D8 ed ho guardato il contenuto dello stack a EBP-11. L'immagine che segue è relativa al contenuto dello stack... guardate la parte evidenziata in grigio:

6.png

si legge distintamente "user32.dll". In pratica, per non avere nel codice la stringa in chiaro "user32.dll" è stata nascosta con il codice che vedete li sopra; questa stringa verrà usata come parametro per LoadLibrary, così da caricare la libreria.
A questo punto proseguo con il disassembly di passwordkeeper.3D1D90 (è la call che vedete qui sopra, indirizzo 0x003D21DA).

4 - Analisi dinamica 2: procedura passwordkeeper.3D1D90​

Anche questa procedura si rivela interessante:

7.png

ma la parte su cui voglio soffermarmi è poco più sotto, in quanto vedo un "fopen" seguito da un "fread":

8.png

il file che viene letto è "passwords.db", citato a inizio articolo. Quando la lettura va a buon fine viene memorizzato ad uno specifico offset (0x3D7828) il valore puntato da EAX:

Codice:
003D1F32 | 83EC 10                     | sub esp,10                                   |
003D1F35 | 8D4C24 2C                   | lea ecx,dword ptr ss:[esp+2C]                |
003D1F39 | 56                          | push esi                                     | esi:"CisCntu"
003D1F3A | E8 11F9FFFF                 | call passwordkeeper.3D1850                   |
003D1F3F | 56                          | push esi                                     | esi:"CisCntu"
003D1F40 | A3 28783D00                 | mov dword ptr ds:[3D7828],eax                |
003D1F45 | E8 D3080000                 | call passwordkeeper.3D281D                   |
003D1F4A | FF7424 0C                   | push dword ptr ss:[esp+C]                    | [esp+C]:"˜\fî"
003D1F4E | FF15 28413D00               | call dword ptr ds:[<&fclose>]                |
003D1F54 | 83C4 08                     | add esp,8                                    |

Per curiosità ho guardato l'indirizzo 0x3D7828... ci sono byte senza molto senso a prima vista; ma se si conoscono alcuni opcode a memoria, si può vedere qualcosa che non può non balzare all'occhio:
Codice:
00EE1CC8  55 8B EC 83 EC 1C 8B 45 08 89 45 E8 8B 4D 0C 89  U.ì.ì..E..Eè.M..

questi sono i primi bytes che si vedono. I primi 3byte mi fanno pensare al prologo di una funzione, PUSH EBP e MOV EBP, ESP. Per ora decido comunque di proseguire, ignorando la cosa.

La chiamata ritorna alla procedura precedente, quella contenente il messaggio di benvenuto. Avviene poi una chiamata a 0x003D2610, che tra le altre cose, legge l'input da tastiera. La procedura ritorna, e chiama un paio di istruzioni sotto un'altra funzione:

Codice:
003D226E | E8 DDEEFFFF                 | call passwordkeeper.3D1150                   |

L'immagine 9 riporta parzialmente questa funzione:

9.png

la parte iniziale della procedura decifra due stringhe: "Invalid password" e "Nice job!". Proseguendo si vede un'altra ricerca con il medesimo meccanismo spiegato sopra:

10.png

la procedura cercata è la MessageBox. Ci sono altre parti analoghe, per altre funzioni (freopen, mblen), ma l'ultima la riporto... se avete letto i precedenti articoli è cosa nota:

11.png

si tratta di VirtualProtect. La procedura viene chiamata poco sotto infatti:

Codice:
003D1478 | 8B75 A0                     | mov esi,dword ptr ss:[ebp-60]                |
003D147B | 8B55 A4                     | mov edx,dword ptr ss:[ebp-5C]                |
003D147E | 8B46 24                     | mov eax,dword ptr ds:[esi+24]                | eax:&"¸:í"
003D1481 | 8D0478                      | lea eax,dword ptr ds:[eax+edi*2]             | eax:&"¸:í", eax+edi*2:"2\rRCºRÛ«AáØY"
003D1484 | 0FB70C10                    | movzx ecx,word ptr ds:[eax+edx]              |
003D1488 | 8B46 1C                     | mov eax,dword ptr ds:[esi+1C]                | eax:&"¸:í"
003D148B | 8D0488                      | lea eax,dword ptr ds:[eax+ecx*4]             | eax:&"¸:í"
003D148E | 8B3410                      | mov esi,dword ptr ds:[eax+edx]               |
003D1491 | 8D45 9C                     | lea eax,dword ptr ss:[ebp-64]                |
003D1494 | 50                          | push eax                                     | eax:&"¸:í"
003D1495 | 6A 40                       | push 40                                      |
003D1497 | FF35 24783D00               | push dword ptr ds:[3D7824]                   |
003D149D | 03F2                        | add esi,edx                                  | edx:"VirtualProtectEx"
003D149F | FF35 28783D00               | push dword ptr ds:[3D7828]                   |
003D14A5 | FFD6                        | call esi                                     |
003D14A7 | 837D C0 10                  | cmp dword ptr ss:[ebp-40],10                 |
003D14AB | 8D4D AC                     | lea ecx,dword ptr ss:[ebp-54]                | [ebp-54]:"Invalid Password"
003D14AE | 8D45 C4                     | lea eax,dword ptr ss:[ebp-3C]                |
003D14B1 | 0F434D AC                   | cmovae ecx,dword ptr ss:[ebp-54]             | [ebp-54]:"Invalid Password"
003D14B5 | 837D D8 10                  | cmp dword ptr ss:[ebp-28],10                 |
003D14B9 | 51                          | push ecx                                     |
003D14BA | 0F4345 C4                   | cmovae eax,dword ptr ss:[ebp-3C]             |
003D14BE | 50                          | push eax                                     | eax:&"¸:í"
003D14BF | FF75 90                     | push dword ptr ss:[ebp-70]                   | [ebp-70]:"sdfasdfasdfdsfa"
003D14C2 | FF75 8C                     | push dword ptr ss:[ebp-74]                   |
003D14C5 | FF75 98                     | push dword ptr ss:[ebp-68]                   |
003D14C8 | FF75 94                     | push dword ptr ss:[ebp-6C]                   |
003D14CB | FF15 28783D00               | call dword ptr ds:[3D7828]                   |

si tratta di CALL ESI (ESI punta a VirtualProtect). Ora vediamo un'altra cosa interessante: l'indirizzo salvato sopra, a seguito della lettura da file, viene usato con VirtualProtect, ma non solo: dall'ultima istruzione che ho riportato potete anche vedere che l'indirizzo è la destinazione di una CALL; i bytes che avevo notato sopra, sono effettivamente il prologo di una funzione quindi.

NOTA: durante la prima "esplorazione" del crackme, ho raggiunto questa parte utilizzando l'indirizzo 0x3D7828: ho settato un breakpoint hardware sull'accesso, scrittura ed esecuzione.

5 - Analisi dinamica: disassembly del codice al nuovo indirizzo​

Ci troviamo ora in un'area che non è eseguibile, ma che contiene del codice eseguibile; o meglio, la sezione in sè non è eseguibile ma grazie a VirtualProtect questi dati ora lo sono. Riporto anche qui alcune istruzioni iniziali:

12.png

poche istruzioni dopo l'entry point ci sono due call "nascoste":
Codice:
01251CE8 | 6A 10                       | push 10                                      |
01251CEA | FF55 E4                     | call dword ptr ss:[ebp-1C]                   |
01251CED | 83C4 04                     | add esp,4                                    |
01251CF0 | 8945 F8                     | mov dword ptr ss:[ebp-8],eax                 |
01251CF3 | 6A 18                       | push 18                                      |
01251CF5 | FF55 E4                     | call dword ptr ss:[ebp-1C]                   |

EBP-1C contiene l'indirizzo di "malloc": viene riservato dello spazio per 2 buffer, di dimensioni 0x10 e 0x18.
Tutta quella parte di codice che pare simile alle precedenti, sta in effetti componendo quella che è una stringa. Arrivati al termine, dove viene inserito il terminatore della stringa, si vede questo guardando in memoria alla locazione puntata da EDX+EAX:

Codice:
00EDF367  20 75 66 70 78 7A 7D 74 4C 7E 23 61 75 7A 7D 74   ufpxz}tL~#auz}t

le istruzioni più importanti seguono di poco quel codice:

Codice:
00EE1F79 | 8B4D F0                     | mov ecx,dword ptr ss:[ebp-10]                |
00EE1F7C | 83C1 01                     | add ecx,1                                    |
00EE1F7F | 894D F0                     | mov dword ptr ss:[ebp-10],ecx                |
00EE1F82 | 837D F0 0F                  | cmp dword ptr ss:[ebp-10],F                  |
00EE1F86 | 7D 7B                       | jge EE2003                                   |
00EE1F88 | 8B55 14                     | mov edx,dword ptr ss:[ebp+14]                | [ebp+14]:"sdfasdfasdfdsfa"
00EE1F8B | 0355 F0                     | add edx,dword ptr ss:[ebp-10]                |
00EE1F8E | 0FBE02                      | movsx eax,byte ptr ds:[edx]                  |
00EE1F91 | 85C0                        | test eax,eax                                 |
00EE1F93 | 75 2B                       | jne EE1FC0                                   |
00EE1F95 | 0FAEE8                      | lfence                                       |
00EE1F98 | 6A 00                       | push 0                                       |
00EE1F9A | 6A 00                       | push 0                                       |
00EE1F9C | 8B4D 1C                     | mov ecx,dword ptr ss:[ebp+1C]                | [ebp+1C]:"Invalid Password"
00EE1F9F | 51                          | push ecx                                     |
00EE1FA0 | 6A 00                       | push 0                                       |
00EE1FA2 | FF55 E8                     | call dword ptr ss:[ebp-18]                   |
00EE1FA5 | 8B55 F8                     | mov edx,dword ptr ss:[ebp-8]                 |
00EE1FA8 | 52                          | push edx                                     |
00EE1FA9 | FF55 F4                     | call dword ptr ss:[ebp-C]                    |
00EE1FAC | 83C4 04                     | add esp,4                                    |
00EE1FAF | 8B45 FC                     | mov eax,dword ptr ss:[ebp-4]                 |
00EE1FB2 | 50                          | push eax                                     |
00EE1FB3 | FF55 F4                     | call dword ptr ss:[ebp-C]                    |
00EE1FB6 | 83C4 04                     | add esp,4                                    |
00EE1FB9 | 32C0                        | xor al,al                                    |
00EE1FBB | E9 AE000000                 | jmp EE206E                                   |
00EE1FC0 | 8B4D F8                     | mov ecx,dword ptr ss:[ebp-8]                 |
00EE1FC3 | 034D F0                     | add ecx,dword ptr ss:[ebp-10]                |
00EE1FC6 | 0FBE11                      | movsx edx,byte ptr ds:[ecx]                  |
00EE1FC9 | 83F2 13                     | xor edx,13                                   |
00EE1FCC | 8B45 14                     | mov eax,dword ptr ss:[ebp+14]                | [ebp+14]:"sdfasdfasdfdsfa"
00EE1FCF | 0345 F0                     | add eax,dword ptr ss:[ebp-10]                |
00EE1FD2 | 0FBE08                      | movsx ecx,byte ptr ds:[eax]                  |
00EE1FD5 | 3BD1                        | cmp edx,ecx                                  |
00EE1FD7 | 74 25                       | je EE1FFE                                    |

restringendo ulteriormente alla parte del controllo:

Codice:
00EE1FC0 | 8B4D F8                     | mov ecx,dword ptr ss:[ebp-8]                 |
00EE1FC3 | 034D F0                     | add ecx,dword ptr ss:[ebp-10]                |
00EE1FC6 | 0FBE11                      | movsx edx,byte ptr ds:[ecx]                  |
00EE1FC9 | 83F2 13                     | xor edx,13                                   |
00EE1FCC | 8B45 14                     | mov eax,dword ptr ss:[ebp+14]                | [ebp+14]:"sdfasdfasdfdsfa"
00EE1FCF | 0345 F0                     | add eax,dword ptr ss:[ebp-10]                |
00EE1FD2 | 0FBE08                      | movsx ecx,byte ptr ds:[eax]                  |
00EE1FD5 | 3BD1                        | cmp edx,ecx                                  |
00EE1FD7 | 74 25                       | je EE1FFE                                    |

EBP-8 punta alla stringa decifrata vista sopra, "ufpxz}tL~#auz}t", mentre EBP+14 punta alla stringa immessa in input. All'indirizzo EBP-10 si trova un contatore del ciclo. L'algoritmo è molto semplice: viene considerato ogni carattere della stringa decifrata a cui viene applicato lo XOR con il valore 0x13; se il valore ottenuto è diverso dal carattere alla i-esima posizione immesso in input, allora il JE non avviene, e il programma termina con il messaggio riguardante la password invalida.

6 - Keygen: otteniamo la password​

E' stato decisamente più difficile arrivare alla fine rispetto all'implementare l'algoritmo per trovare la password corretta. Sono infatti sufficienti due righe in C, per avere la password:

C:
#include <stdio.h>

int main()
{
    char *str_decrypted = "ufpxz}tL~#auz}t";

    int len = 0;
    while(len < 15)
    {
        printf("%c", (str_decrypted[len++] ^ 0x13));
    }

    return 0;
}

eseguendolo si ottiene fucking_m0rfing. Inserendolo come input abbiamo il messaggio:

13.png

6 - Conclusione​

Come le volte precedenti mi auguro che la lettura sia stata piacevole, e se avete domande, scrivete qui sotto.
Se trovate errori di qualche tipo, segnalatemeli pure; ho scritto l'articolo in serata, e l'ho ricontrollato un paio di volte, ma vista l'ora...
 

Crackme #6, Password Keeper​

Autore crackme: n30np14gu3


0 - Introduzione​

Questo crackme rientra sicuramente tra i più interessanti tra quelli presentati qui. Non è stato semplice a prima vista, specie perchè ho dovuto interrompere il debug per diversi giorni... e quando ci ho rimesso mano, non ricordavo nulla (la prima esplorazione non prevedeva raccolta di informazioni; è stata una pessima scelta).
Se siete interessati ad altro materiale di questo tipo, potete consultare le Guide degli gli utenti.

In questo crackme ci sono alcune cose davvero interessanti (VirtualProtect, API Obfuscation), quindi vi suggerirei di proseguire con la lettura. ? Tecniche come queste (in particolare quella che riguarda le API) vengono utilizzate sia per la protezione del software, sia per lo scopo contrario (malware), seppur meno avanzate di altre (virtual machine, in testa).

1 - Analisi statica​

Come sempre per prima cosa mi avvalgo di due strumenti, per dare un'occhiata al file EXE: RDG Packer Detector e CF Explorer.
RDG Packer Detector segnala un possibile "isDebuggerPresent()" ma non riporta informazioni sulle compressioni, non rileva nulla:


Guardando la import directory ci sono alcune librerie, e si nota in effetti KERNEL32.DLL, dove si può notare isDebuggerPresent:

Visualizza allegato 426512

Ho deciso di effettuare un altro controllo, utilizzando un'utility di cui non mi sembra di aver mai accennato nei precedenti articoli. Si chiama strings, e lo trovate su Sysinternals. In poche parole riporta tutte le stringhe (sequenze di ASCII/Unicode) presenti nell'eseguibile.
Questo un output del programma lanciandolo senza argomenti:

Codice:
Strings v2.54 - Search for ANSI and Unicode strings in binary images.
Copyright (C) 1999-2021 Mark Russinovich
Sysinternals - www.sysinternals.com

usage: strings [-a] [-f offset] [-b bytes] [-n length] [-o] [-s] [-u] <file or directory>
-a     Ascii-only search (Unicode and Ascii is default)
-b     Bytes of file to scan
-f     File offset at which to start scanning.
-o     Print offset in file string was located
-n     Minimum string length (default is 3)
-s     Recurse subdirectories
-u     Unicode-only search (Unicode and Ascii is default)
-nobanner
       Do not display the startup banner and copyright message.

evito di riportare l'intero output, mi limito alle poche stringhe interessanti che si possono vedere:
Codice:
string too long
please, check passwords.db file
Welcome to Super Password Keeper
Enter password for decryption->
pause

Non è un buon segno, in quanto non sono presenti messaggi di "ok" o "fallimento", di conseguenza è altamente probabile che le stringhe non siano in chiaro.
La cartella che contiene l'eseguibile ha al suo interno un altro file, chiamato "passwords.db", il cui contenuto risulta praticamente non leggibile.

2 - Prima Esecuzione​

Lanciando l'eseguibile e inserendo una password a caso, ottengo questo output:


Qui inizio a capire che la cosa sarà interessante...
Il messaggio ricevuto è una stringa non presente in chiaro nell'exe, e la finestra che si vede è una MessageBox, che tuttavia non risulta tra le funzioni importate. A questo punto è ora di aprire il debugger...

3 - Analisi dinamica (con x32dbg)​

Sapendo che ci sono stringhe in chiaro e che si tratta di un messaggio di benvenuto, cerco quelle, così da raggiungere subito quella procedura e settare un breakpoint (bp). Già le istruzioni sopra a questi messaggi si rivelano interessanti, come potete vedere dallo screen sottostante:


NOTA: ho già settato alcuni bp, l'articolo e gli screen li sto facendo successivamente a seguito della risoluzione (non sono mai sicuro di arrivare al termine ?).

Ho già visto cose di quel tipo, di solito si tratta di un modo per "nascondere" le stringhe nell'eseguibile. Risalgo la procedura sino all'entry point della stessa e vedo che le cose... migliorano... guardate l'immagine sottostante:

le prime istruzioni sulle quali mi cade l'occhio sono:

Codice:
003D20DB | 64:A1 30000000              | mov eax,dword ptr fs:[30]                    |
003D20E1 | 8B40 0C                     | mov eax,dword ptr ds:[eax+C]                 |
003D20E4 | 8B40 0C                     | mov eax,dword ptr ds:[eax+C]                 |
003D20E7 | 8B70 18                     | mov esi,dword ptr ds:[eax+18]                |

siamo in x86, quindi il registro FS punta a una struttura dati chiamata TEB (Thread Environment Block), che contiene tutte le info sul Thread in esecuzione. L'offset 0x30 contiene un puntatore a un'altra struttura, PEB (Process Environment Block). Anche questa sequenza di istruzioni mi fa già capire cosa accade, ma ho la certezza controllando gli offset che vengono sommati.

Su MSDN potete trovare tutte le info, io riporto solo la struttura:

C:
typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  PVOID                         Reserved4[3];
  PVOID                         AtlThunkSListPtr;
  PVOID                         Reserved5;
  ULONG                         Reserved6;
  PVOID                         Reserved7;
  ULONG                         Reserved8;
  ULONG                         AtlThunkSListPtr32;
  PVOID                         Reserved9[45];
  BYTE                          Reserved10[96];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved11[128];
  PVOID                         Reserved12[1];
  ULONG                         SessionId;
} PEB, *PPEB;

se contate 0xC (12d) bytes, arrivate al membro chiamato Ldr, che è di tipo PPEB_LDR_DATA:
C:
typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];
  PVOID      Reserved2[3];
  LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

ecco, viene selezionato InMemoryOrderModuleList. Dal nome avrete già intuito magari di cosa si tratta: in poche parole è una linked list dove ogni elemento contiene info su una DLL.
Tutto il codice che segue e che riporto anche qui per chiarezza, non è altro che un loop; vengono utilizzati alcuni "ordinal" (è un identificativo numerico che consente di individuare una specifica funzione, trovate tute le info guardando il PE Header; in questo caso in realtà è probabile sia un checksum, non mi sembra in chiaro).

Codice:
003D2101 | 3BCE                        | cmp ecx,esi                                  | ecx:"LoadLibraryExA"
003D2103 | 74 4F                       | je passwordkeeper.3D2154                     |
003D2105 | 8B79 18                     | mov edi,dword ptr ds:[ecx+18]                | ecx+18:"ryExW"
003D2108 | 85FF                        | test edi,edi                                 |
003D210A | 74 48                       | je passwordkeeper.3D2154                     |
003D210C | 8B49 20                     | mov ecx,dword ptr ds:[ecx+20]                | ecx:"LoadLibraryExA", ecx+20:"adLibraryW"
003D210F | 8D1CB9                      | lea ebx,dword ptr ds:[ecx+edi*4]             | ebx:"ÕË\t", ecx+edi*4:"Exception"
003D2112 | 03DE                        | add ebx,esi                                  | ebx:"ÕË\t"
003D2114 | 8B4B FC                     | mov ecx,dword ptr ds:[ebx-4]                 | ecx:"LoadLibraryExA", ebx-4:"–Ë\t"
003D2117 | 8D5B FC                     | lea ebx,dword ptr ds:[ebx-4]                 | ebx:"ÕË\t", ebx-4:"–Ë\t"
003D211A | 03CE                        | add ecx,esi                                  | ecx:"LoadLibraryExA"
003D211C | 4F                          | dec edi                                      |
003D211D | BE C59D1C81                 | mov esi,811C9DC5                             |
003D2122 | 8A11                        | mov dl,byte ptr ds:[ecx]                     | ecx:"LoadLibraryExA"
003D2124 | 41                          | inc ecx                                      | ecx:"LoadLibraryExA"
003D2125 | 84D2                        | test dl,dl                                   |
003D2127 | 74 24                       | je passwordkeeper.3D214D                     |
003D2129 | 0F1F80 00000000             | nop dword ptr ds:[eax],eax                   |
003D2130 | 0FBED2                      | movsx edx,dl                                 |
003D2133 | 8D49 01                     | lea ecx,dword ptr ds:[ecx+1]                 | ecx:"LoadLibraryExA", ecx+1:"oadLibraryExA"
003D2136 | 33D6                        | xor edx,esi                                  |
003D2138 | 69F2 93010001               | imul esi,edx,1000193                         |
003D213E | 8A51 FF                     | mov dl,byte ptr ds:[ecx-1]                   |
003D2141 | 84D2                        | test dl,dl                                   |
003D2143 | 75 EB                       | jne passwordkeeper.3D2130                    |
003D2145 | 81FE 0F07B253               | cmp esi,53B2070F                             |
003D214B | 74 0B                       | je passwordkeeper.3D2158                     |
003D214D | 8B70 18                     | mov esi,dword ptr ds:[eax+18]                |
003D2150 | 85FF                        | test edi,edi                                 |
003D2152 | 75 C0                       | jne passwordkeeper.3D2114                    |
003D2154 | 8B00                        | mov eax,dword ptr ds:[eax]                   | eax:&"¸:í", [eax]:&"ˆ”í"
003D2156 | EB 8F                       | jmp passwordkeeper.3D20E7                    |
003D2158 | 8B45 C0                     | mov eax,dword ptr ss:[ebp-40]                |

per capire di che funzione si tratta, ho settato un bp all'ultima istruzione che vedete qui sopra, e come notate dai commenti, quando l'esecuziione si blocca al bp, si vede che si tratta di LoadLibrary (già dal nome si intuisce l'utilizzo: infatti carica una specifica libreria che viene passata come parametro).
Qualche istruzione sotto e ci ritroviamo di fronte a quanto ho mostrato nello screen sopra:

Codice:
003D2171 | 74 67                       | je passwordkeeper.3D21DA                     |
003D2173 | C645 E4 45                  | mov byte ptr ss:[ebp-1C],45                  | 45:'E'
003D2177 | B0 30                       | mov al,30                                    | 30:'0'
003D2179 | 3245 E4                     | xor al,byte ptr ss:[ebp-1C]                  |
003D217C | B1 36                       | mov cl,36                                    | 36:'6'
003D217E | 324D E4                     | xor cl,byte ptr ss:[ebp-1C]                  |
003D2181 | B4 76                       | mov ah,76                                    | 76:'v'
003D2183 | 8845 E5                     | mov byte ptr ss:[ebp-1B],al                  |
003D2186 | B2 20                       | mov dl,20                                    | 20:' '
003D2188 | 884D E6                     | mov byte ptr ss:[ebp-1A],cl                  |
003D218B | B5 77                       | mov ch,77                                    | 77:'w'
003D218D | 8A4D E4                     | mov cl,byte ptr ss:[ebp-1C]                  |
003D2190 | B6 6B                       | mov dh,6B                                    | 6B:'k'
003D2192 | C645 CB 29                  | mov byte ptr ss:[ebp-35],29                  | 29:')'
003D2196 | 32E1                        | xor ah,cl                                    |
003D2198 | 8A45 CB                     | mov al,byte ptr ss:[ebp-35]                  |
003D219B | B3 37                       | mov bl,37                                    | 37:'7'
003D219D | 32C1                        | xor al,cl                                    |
003D219F | C645 CA 29                  | mov byte ptr ss:[ebp-36],29                  | 29:')'
003D21A3 | 8845 ED                     | mov byte ptr ss:[ebp-13],al                  |
003D21A6 | B7 21                       | mov bh,21                                    | 21:'!'
003D21A8 | 8A45 CA                     | mov al,byte ptr ss:[ebp-36]                  |
003D21AB | 32D1                        | xor dl,cl                                    |
003D21AD | 32C1                        | xor al,cl                                    |
003D21AF | 8865 E9                     | mov byte ptr ss:[ebp-17],ah                  |
003D21B2 | 8845 EE                     | mov byte ptr ss:[ebp-12],al                  |
003D21B5 | 32D9                        | xor bl,cl                                    |
003D21B7 | 8D45 E5                     | lea eax,dword ptr ss:[ebp-1B]                |
003D21BA | C645 EF 00                  | mov byte ptr ss:[ebp-11],0                   |
003D21BE | 32E9                        | xor ch,cl                                    |
003D21C0 | 8855 E7                     | mov byte ptr ss:[ebp-19],dl                  |
003D21C3 | 32F1                        | xor dh,cl                                    |
003D21C5 | 885D E8                     | mov byte ptr ss:[ebp-18],bl                  |
003D21C8 | 32F9                        | xor bh,cl                                    |
003D21CA | 886D EA                     | mov byte ptr ss:[ebp-16],ch                  |
003D21CD | 50                          | push eax                                     |
003D21CE | 8875 EB                     | mov byte ptr ss:[ebp-15],dh                  |
003D21D1 | 887D EC                     | mov byte ptr ss:[ebp-14],bh                  |
003D21D4 | C645 EF 00                  | mov byte ptr ss:[ebp-11],0                   |
003D21D8 | FFD6                        | call esi                                     |
003D21DA | E8 B1FBFFFF                 | call passwordkeeper.3D1D90                   |
003D21DF | 8B0D 50403D00               | mov ecx,dword ptr ds:[<&?cout@std@@3V?$basic | 003D4050:&"`0år"
003D21E5 | 68 20253D00                 | push passwordkeeper.3D2520                   |
003D21EA | 84C0                        | test al,al                                   |
003D21EC | 75 17                       | jne passwordkeeper.3D2205                    |
003D21EE | BA F0413D00                 | mov edx,passwordkeeper.3D41F0                | 3D41F0:"please, check passwords.db file"
003D21F3 | E8 E8000000                 | call passwordkeeper.3D22E0                   |
003D21F8 | 8BC8                        | mov ecx,eax                                  |
003D21FA | FF15 48403D00               | call dword ptr ds:[<&??5?$basic_istream@DU?$ |
003D2200 | E9 B2000000                 | jmp passwordkeeper.3D22B7                    |
003D2205 | BA 10423D00                 | mov edx,passwordkeeper.3D4210                | 3D4210:"Welcome to Super Password Keeper"
003D220A | E8 D1000000                 | call passwordkeeper.3D22E0                   |

anche qui, per evitare di capire e farmi i calcoli "a mano" ho settato un bp all'indirizzo 0x003D21D8 ed ho guardato il contenuto dello stack a EBP-11. L'immagine che segue è relativa al contenuto dello stack... guardate la parte evidenziata in grigio:


si legge distintamente "user32.dll". In pratica, per non avere nel codice la stringa in chiaro "user32.dll" è stata nascosta con il codice che vedete li sopra; questa stringa verrà usata come parametro per LoadLibrary, così da caricare la libreria.
A questo punto proseguo con il disassembly di passwordkeeper.3D1D90 (è la call che vedete qui sopra, indirizzo 0x003D21DA).

4 - Analisi dinamica 2: procedura passwordkeeper.3D1D90​

Anche questa procedura si rivela interessante:


ma la parte su cui voglio soffermarmi è poco più sotto, in quanto vedo un "fopen" seguito da un "fread":


il file che viene letto è "passwords.db", citato a inizio articolo. Quando la lettura va a buon fine viene memorizzato ad uno specifico offset (0x3D7828) il valore puntato da EAX:

Codice:
003D1F32 | 83EC 10                     | sub esp,10                                   |
003D1F35 | 8D4C24 2C                   | lea ecx,dword ptr ss:[esp+2C]                |
003D1F39 | 56                          | push esi                                     | esi:"CisCntu"
003D1F3A | E8 11F9FFFF                 | call passwordkeeper.3D1850                   |
003D1F3F | 56                          | push esi                                     | esi:"CisCntu"
003D1F40 | A3 28783D00                 | mov dword ptr ds:[3D7828],eax                |
003D1F45 | E8 D3080000                 | call passwordkeeper.3D281D                   |
003D1F4A | FF7424 0C                   | push dword ptr ss:[esp+C]                    | [esp+C]:"˜\fî"
003D1F4E | FF15 28413D00               | call dword ptr ds:[<&fclose>]                |
003D1F54 | 83C4 08                     | add esp,8                                    |

Per curiosità ho guardato l'indirizzo 0x3D7828... ci sono byte senza molto senso a prima vista; ma se si conoscono alcuni opcode a memoria, si può vedere qualcosa che non può non balzare all'occhio:
Codice:
00EE1CC8  55 8B EC 83 EC 1C 8B 45 08 89 45 E8 8B 4D 0C 89  U.ì.ì..E..Eè.M..

questi sono i primi bytes che si vedono. I primi 3byte mi fanno pensare al prologo di una funzione, PUSH EBP e MOV EBP, ESP. Per ora decido comunque di proseguire, ignorando la cosa.

La chiamata ritorna alla procedura precedente, quella contenente il messaggio di benvenuto. Avviene poi una chiamata a 0x003D2610, che tra le altre cose, legge l'input da tastiera. La procedura ritorna, e chiama un paio di istruzioni sotto un'altra funzione:

Codice:
003D226E | E8 DDEEFFFF                 | call passwordkeeper.3D1150                   |

L'immagine 9 riporta parzialmente questa funzione:


la parte iniziale della procedura decifra due stringhe: "Invalid password" e "Nice job!". Proseguendo si vede un'altra ricerca con il medesimo meccanismo spiegato sopra:


la procedura cercata è la MessageBox. Ci sono altre parti analoghe, per altre funzioni (freopen, mblen), ma l'ultima la riporto... se avete letto i precedenti articoli è cosa nota:


si tratta di VirtualProtect. La procedura viene chiamata poco sotto infatti:

Codice:
003D1478 | 8B75 A0                     | mov esi,dword ptr ss:[ebp-60]                |
003D147B | 8B55 A4                     | mov edx,dword ptr ss:[ebp-5C]                |
003D147E | 8B46 24                     | mov eax,dword ptr ds:[esi+24]                | eax:&"¸:í"
003D1481 | 8D0478                      | lea eax,dword ptr ds:[eax+edi*2]             | eax:&"¸:í", eax+edi*2:"2\rRCºRÛ«AáØY"
003D1484 | 0FB70C10                    | movzx ecx,word ptr ds:[eax+edx]              |
003D1488 | 8B46 1C                     | mov eax,dword ptr ds:[esi+1C]                | eax:&"¸:í"
003D148B | 8D0488                      | lea eax,dword ptr ds:[eax+ecx*4]             | eax:&"¸:í"
003D148E | 8B3410                      | mov esi,dword ptr ds:[eax+edx]               |
003D1491 | 8D45 9C                     | lea eax,dword ptr ss:[ebp-64]                |
003D1494 | 50                          | push eax                                     | eax:&"¸:í"
003D1495 | 6A 40                       | push 40                                      |
003D1497 | FF35 24783D00               | push dword ptr ds:[3D7824]                   |
003D149D | 03F2                        | add esi,edx                                  | edx:"VirtualProtectEx"
003D149F | FF35 28783D00               | push dword ptr ds:[3D7828]                   |
003D14A5 | FFD6                        | call esi                                     |
003D14A7 | 837D C0 10                  | cmp dword ptr ss:[ebp-40],10                 |
003D14AB | 8D4D AC                     | lea ecx,dword ptr ss:[ebp-54]                | [ebp-54]:"Invalid Password"
003D14AE | 8D45 C4                     | lea eax,dword ptr ss:[ebp-3C]                |
003D14B1 | 0F434D AC                   | cmovae ecx,dword ptr ss:[ebp-54]             | [ebp-54]:"Invalid Password"
003D14B5 | 837D D8 10                  | cmp dword ptr ss:[ebp-28],10                 |
003D14B9 | 51                          | push ecx                                     |
003D14BA | 0F4345 C4                   | cmovae eax,dword ptr ss:[ebp-3C]             |
003D14BE | 50                          | push eax                                     | eax:&"¸:í"
003D14BF | FF75 90                     | push dword ptr ss:[ebp-70]                   | [ebp-70]:"sdfasdfasdfdsfa"
003D14C2 | FF75 8C                     | push dword ptr ss:[ebp-74]                   |
003D14C5 | FF75 98                     | push dword ptr ss:[ebp-68]                   |
003D14C8 | FF75 94                     | push dword ptr ss:[ebp-6C]                   |
003D14CB | FF15 28783D00               | call dword ptr ds:[3D7828]                   |

si tratta di CALL ESI (ESI punta a VirtualProtect). Ora vediamo un'altra cosa interessante: l'indirizzo salvato sopra, a seguito della lettura da file, viene usato con VirtualProtect, ma non solo: dall'ultima istruzione che ho riportato potete anche vedere che l'indirizzo è la destinazione di una CALL; i bytes che avevo notato sopra, sono effettivamente il prologo di una funzione quindi.

NOTA: durante la prima "esplorazione" del crackme, ho raggiunto questa parte utilizzando l'indirizzo 0x3D7828: ho settato un breakpoint hardware sull'accesso, scrittura ed esecuzione.

5 - Analisi dinamica: disassembly del codice al nuovo indirizzo​

Ci troviamo ora in un'area che non è eseguibile, ma che contiene del codice eseguibile; o meglio, la sezione in sè non è eseguibile ma grazie a VirtualProtect questi dati ora lo sono. Riporto anche qui alcune istruzioni iniziali:


poche istruzioni dopo l'entry point ci sono due call "nascoste":
Codice:
01251CE8 | 6A 10                       | push 10                                      |
01251CEA | FF55 E4                     | call dword ptr ss:[ebp-1C]                   |
01251CED | 83C4 04                     | add esp,4                                    |
01251CF0 | 8945 F8                     | mov dword ptr ss:[ebp-8],eax                 |
01251CF3 | 6A 18                       | push 18                                      |
01251CF5 | FF55 E4                     | call dword ptr ss:[ebp-1C]                   |

EBP-1C contiene l'indirizzo di "malloc": viene riservato dello spazio per 2 buffer, di dimensioni 0x10 e 0x18.
Tutta quella parte di codice che pare simile alle precedenti, sta in effetti componendo quella che è una stringa. Arrivati al termine, dove viene inserito il terminatore della stringa, si vede questo guardando in memoria alla locazione puntata da EDX+EAX:

Codice:
00EDF367  20 75 66 70 78 7A 7D 74 4C 7E 23 61 75 7A 7D 74   ufpxz}tL~#auz}t

le istruzioni più importanti seguono di poco quel codice:

Codice:
00EE1F79 | 8B4D F0                     | mov ecx,dword ptr ss:[ebp-10]                |
00EE1F7C | 83C1 01                     | add ecx,1                                    |
00EE1F7F | 894D F0                     | mov dword ptr ss:[ebp-10],ecx                |
00EE1F82 | 837D F0 0F                  | cmp dword ptr ss:[ebp-10],F                  |
00EE1F86 | 7D 7B                       | jge EE2003                                   |
00EE1F88 | 8B55 14                     | mov edx,dword ptr ss:[ebp+14]                | [ebp+14]:"sdfasdfasdfdsfa"
00EE1F8B | 0355 F0                     | add edx,dword ptr ss:[ebp-10]                |
00EE1F8E | 0FBE02                      | movsx eax,byte ptr ds:[edx]                  |
00EE1F91 | 85C0                        | test eax,eax                                 |
00EE1F93 | 75 2B                       | jne EE1FC0                                   |
00EE1F95 | 0FAEE8                      | lfence                                       |
00EE1F98 | 6A 00                       | push 0                                       |
00EE1F9A | 6A 00                       | push 0                                       |
00EE1F9C | 8B4D 1C                     | mov ecx,dword ptr ss:[ebp+1C]                | [ebp+1C]:"Invalid Password"
00EE1F9F | 51                          | push ecx                                     |
00EE1FA0 | 6A 00                       | push 0                                       |
00EE1FA2 | FF55 E8                     | call dword ptr ss:[ebp-18]                   |
00EE1FA5 | 8B55 F8                     | mov edx,dword ptr ss:[ebp-8]                 |
00EE1FA8 | 52                          | push edx                                     |
00EE1FA9 | FF55 F4                     | call dword ptr ss:[ebp-C]                    |
00EE1FAC | 83C4 04                     | add esp,4                                    |
00EE1FAF | 8B45 FC                     | mov eax,dword ptr ss:[ebp-4]                 |
00EE1FB2 | 50                          | push eax                                     |
00EE1FB3 | FF55 F4                     | call dword ptr ss:[ebp-C]                    |
00EE1FB6 | 83C4 04                     | add esp,4                                    |
00EE1FB9 | 32C0                        | xor al,al                                    |
00EE1FBB | E9 AE000000                 | jmp EE206E                                   |
00EE1FC0 | 8B4D F8                     | mov ecx,dword ptr ss:[ebp-8]                 |
00EE1FC3 | 034D F0                     | add ecx,dword ptr ss:[ebp-10]                |
00EE1FC6 | 0FBE11                      | movsx edx,byte ptr ds:[ecx]                  |
00EE1FC9 | 83F2 13                     | xor edx,13                                   |
00EE1FCC | 8B45 14                     | mov eax,dword ptr ss:[ebp+14]                | [ebp+14]:"sdfasdfasdfdsfa"
00EE1FCF | 0345 F0                     | add eax,dword ptr ss:[ebp-10]                |
00EE1FD2 | 0FBE08                      | movsx ecx,byte ptr ds:[eax]                  |
00EE1FD5 | 3BD1                        | cmp edx,ecx                                  |
00EE1FD7 | 74 25                       | je EE1FFE                                    |

restringendo ulteriormente alla parte del controllo:

Codice:
00EE1FC0 | 8B4D F8                     | mov ecx,dword ptr ss:[ebp-8]                 |
00EE1FC3 | 034D F0                     | add ecx,dword ptr ss:[ebp-10]                |
00EE1FC6 | 0FBE11                      | movsx edx,byte ptr ds:[ecx]                  |
00EE1FC9 | 83F2 13                     | xor edx,13                                   |
00EE1FCC | 8B45 14                     | mov eax,dword ptr ss:[ebp+14]                | [ebp+14]:"sdfasdfasdfdsfa"
00EE1FCF | 0345 F0                     | add eax,dword ptr ss:[ebp-10]                |
00EE1FD2 | 0FBE08                      | movsx ecx,byte ptr ds:[eax]                  |
00EE1FD5 | 3BD1                        | cmp edx,ecx                                  |
00EE1FD7 | 74 25                       | je EE1FFE                                    |

EBP-8 punta alla stringa decifrata vista sopra, "ufpxz}tL~#auz}t", mentre EBP+14 punta alla stringa immessa in input. All'indirizzo EBP-10 si trova un contatore del ciclo. L'algoritmo è molto semplice: viene considerato ogni carattere della stringa decifrata a cui viene applicato lo XOR con il valore 0x13; se il valore ottenuto è diverso dal carattere alla i-esima posizione immesso in input, allora il JE non avviene, e il programma termina con il messaggio riguardante la password invalida.

6 - Keygen: otteniamo la password​

E' stato decisamente più difficile arrivare alla fine rispetto all'implementare l'algoritmo per trovare la password corretta. Sono infatti sufficienti due righe in C, per avere la password:

C:
#include <stdio.h>

int main()
{
    char *str_decrypted = "ufpxz}tL~#auz}t";

    int len = 0;
    while(len < 15)
    {
        printf("%c", (str_decrypted[len++] ^ 0x13));
    }

    return 0;
}

eseguendolo si ottiene fucking_m0rfing. Inserendolo come input abbiamo il messaggio:

6 - Conclusione​

Come le volte precedenti mi auguro che la lettura sia stata piacevole, e se avete domande, scrivete qui sotto.
Se trovate errori di qualche tipo, segnalatemeli pure; ho scritto l'articolo in serata, e l'ho ricontrollato un paio di volte, ma vista l'ora...

Come sempre un lavoro degno di nota! Bravo.
 
bel tutorial li ho recuperati quasi tutti, mi piacerebbe vedere anche qualche crackme con qualche packer intermedio(magari non UPX) per vedere come si ragiona in quei casi. Grazie per questi tutorial comunque ben fatti e ben spiegati
 
bel tutorial li ho recuperati quasi tutti, mi piacerebbe vedere anche qualche crackme con qualche packer intermedio(magari non UPX) per vedere come si ragiona in quei casi. Grazie per questi tutorial comunque ben fatti e ben spiegati
Ciao, grazie!

In origine l'idea era andare un pò per gradi, volevo introdurre prima UPX e poi altro. Il vero problema sta diventando il tempo: stavo scrivendo un articolo sul crackme 7, che era anche interessante, ma non ho avuto tempo ed energie per scrivere un PoC ed è tutto li fermo dal mese di ottobre/novembre. C'erano alcune protezioni, se ricordo bene erano verifiche sul tempo trascorso più del codice automodificante che generava un paio di istruzioni, dove poi avrebbe saltato per proseguire l'esecuzione.

Non appena mi riprendo proseguo; l'idea poi sarebbe portare prima UPX, magari facendo unpacking manuale e non.
 
Pubblicità
Pubblicità
Indietro
Top