Zoom Icon

Corso UIC Newbies 10

From UIC

Puntatori a funzione e registry

Contents


Infos
Author: Syscalo
Email: x4sys@iname.com
Website: http://syscalo.cjb.net
Date: 12/04/2001 (dd/mm/yyyy)
Level: Working brain required
Language: Italian Image:Flag_Italian.gif
Comments:



Introduzione

Questo programma vuole essere un plug-in ai precedenti tutorial della sezione per newbies. Dato che non mi sembra che sia mai stato trattato esplicitamente l'argomento puntatori a funzione, ho pensato di farlo io. Ovviamente i puntatori a funzione non sono nati come tecnica di protezione per il sw, ma con qualche accorgimento possono essere sfruttati anche per questo. Qui farò qualcosa di mooolto semplice, ma se ci mettete un po' di fantasia vedrete che combinerete qualcosa di meglio.


Tools


Essay

L'intento di questo tutorial è di darvi lo spunto per qualcosa di nuovo, quindi non mi metterò a spiegarvi come intercettare le chiamate alla lettura del registry o l'intercettazione delle msgbox; tutte queste cose sono state trattate negli altri tutorial!

L'unica cosa che verrà vista disassemblando è la parte dei puntatori a funzione. Per tutto il resto metto il codice sorgente C. Se non conoscete il C non preoccupatevi, il codice è ben commentato.

Un'ultima cosa: quello che dovreste fare voi è capire come funziona il programma, come gioca con le chiavi del registry, e come vengono utilizzati i puntatori a funzione, ovviamente senza leggere il codice sorgente ;-p Le stringhe utilizzate nel programma sono lasciate tutte in chiaro, e non sono stati usati trucchi o inganni, proprio perché lo scopo del programma non è di essere crackato, ma di essere analizzato! Poi ognuno può fare quello che vuole.

Ed ora la parte interessante del disassemblato:

Questa è la funzione principale del programma; qui ho inserito un piccolo controllo che potrebbe darvi qualche ispirazione sull'uso dei puntatori a funzione per proteggere i vostri programmi. La cosa è molto semplice: se il puntatore della funzione da eseguire è uguale alla funzione che indica che siete riusciti a fregare il programma, viene ricontrollata la condizione di verifica sul valore letto dal registry; se questo non combacia vuol dire che qualcuno a manomesso il programma e quindi noi reagiamo a dovere ;-)


sub_401606 proc near
push ebp
mov ebp, esp
push edi
call sub_40144B
call sub_40150F
lea edi, ds:4013E4h
cmp dword_402040, edi
jnz short loc_401642 // se non è la funzione che indica che siamo bravi... (A)
push offset aCrked
push offset unk_402050
call j_strcmp // altrimenti controlla anche la condizione sul valore letto
dal registry

add esp, 8
cmp eax, 0
jz short loc_401642 // se è verificata allora è tutto a posto... (A)
push 0
push 6
call j_ExitWindowsEx // altrimenti reagiamo di conseguenza ;-)

loc_401642:
call dword_402040 // (A) ...prosegue normalmente con la funzione assegnata
al puntatore

xor eax, eax
pop edi
pop ebp
retn 10h
sub_401606 endp

Ed ora la parte della scelta; casualmente ;-p l'indirizzo a cui viene assegnata la funzione da eseguire è lo stesso della call a loc_401642.


loc_4015A3:
push offset aCrked
push offset unk_402050
call j_strcmp
add esp, 8
cmp eax, 0
jnz short loc_4015C8
lea edi, ds:4013E4h // copia l'indirizzo della funzione da assegnare
in un registro

mov dword_402040, edi // copia il valore nella variabile all'indirizzo
402040

jmp short loc_4015F9

loc_4015C8:
lea edi, ds:4013F8h
mov dword_402040, edi // e così fa qui
jmp short loc_4015F9

loc_4015D6:
cmp dword_402048, 0
jz short loc_4015ED
lea edi, ds:40140Ch
mov dword_402040, edi // e così fa qui
jmp short loc_4015F9

loc_4015ED:
lea edi, ds:4013F8h
mov dword_402040, edi // e così fa qui

loc_4015F9:
push dword_40203C
call j_RegCloseKey
pop edi
retn
sub_40150F endp

Le condizioni per fare in modo che il programma si complimenti con voi le potete leggere nel sorgente e confrontarle con il codice disassemblato.


#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#define N 50
#define INITSTR "Today is a nice day for me! ;-p"

void (*doit)(void); // puntatore a funzione

char *key="software\\doit"; // chiave da aprire
PHKEY khandle; // handle per la chiave aperta
long exist; // valore di ritorno dall'apertura della chiave
long result[2]; // valori di ritorno dalla lettura delle chiavi
LPDWORD tipo; // tipo del valore letto
char vk1[N]; // buffer per il valore letto da k1
char vk2[N]; // buffer per il valore letto da k2
unsigned long lk1=N; // dimensione del buffer vk1
unsigned long lk2=N; // dimensione del buffer vk2
char *lpclass="GCPCLASS_LATIN"; // classe per la chiave key


void dho(void)
{
MessageBox(0, "Today is a very fucking day for me :-\\\n \
But not for you!! You did it again: CRACKED ;-D", "oOoOoOo", MB_OK);
}

void mmm(void)
{
MessageBox(0, "Ough... Are you fucking me? :-x", "oOoOoOo", MB_OK);
}

void hello(void)
{
// legge il valore k2
lk2=N;
RegQueryValueEx(khandle, "k2", 0, &tipo, vk2, &lk2);
// e visualizza una msgbox con il contenuto di k2 */
MessageBox(0, vk2, "oOoOoOo", MB_OK);
}


void init(void)
{
unsigned long created;

// apre la chiave key, la crea se non esiste */
RegCreateKeyEx(HKEY_LOCAL_MACHINE, key, 0, lpclass, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, 0, &khandle, &created);

// se la chiave è stata creata */
if(REG_CREATED_NEW_KEY==created)
{
// aggiungi il valore k2 */
RegSetValueEx(khandle, "k2", 0, REG_SZ, INITSTR, strlen(INITSTR));
// legge il valore k2 */
RegQueryValueEx(khandle, "k2", 0, &tipo, vk2, &lk2);
// e visualizza una msgbox con il contenuto di k2 */
MessageBox(0, vk2, "oOoOoOo", MB_OK);
// chiude la chiave key */
RegCloseKey(khandle);
exit(0);
}

// chiude la chiave key */
RegCloseKey(khandle);
return;
}


void check_it(void)
{
// apre la chiave key, se non esiste... */
if(0!=RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_ALL_ACCESS, &khandle))
// ...riavvia il sistema */
ExitWindowsEx(EWX_REBOOT|EWX_FORCE, 0);


// legge il valore k1 */
result[0]=RegQueryValueEx(khandle, "k1", 0, &tipo, vk1, &lk1);

// legge il valore k2 */
result[1]=RegQueryValueEx(khandle, "k2", 0, &tipo, vk2, &lk2);


// NOTA: esiste <-> ==0 */

// se k2 non esiste */
if(0!=result[1])
// se k1 non esiste... */
if(0!=result[0])
// ...riavvia il sistema */
ExitWindowsEx(EWX_REBOOT|EWX_FORCE, 0);
// altrimenti (k1 esiste) */
else
// se il contenuto è corretto */
if(0==strcmp(vk1, "crked"))
/* dho */
doit=dho;
// altrimenti (contenuto sbagliato) */
else
// mmm */
doit=mmm;
// altrimenti (k2 esiste) */
else
// se k1 non esiste */
if(0!=result[0])
// hello */
doit=hello;
// altrimenti (k1 esiste) */
else
// mmm */
doit=mmm;


// chiude la chiave key */
RegCloseKey(khandle);
return;
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
init();

check_it();

// se la funzione è dho, ma la stringa è diversa dal valore corretto */
if(doit==dho && 0!=strcmp(vk1, "crked"))
// vuol dire che qlc ha manomesso il prg quindi gli facciamo un piccolo scherzo */
ExitWindowsEx(EWX_REBOOT|EWX_FORCE, 0);

// altrimenti eseguiamo normalmente la funzione */
doit();

return 0;
}


Note Finali

Questo tutorial è dedicato a voi per salvarvi dal tentativo di AndreaGeddon di diventare il dominatore assoluto dell'umanità. Con i suoi tutorial e le partite a bowling ;-p vuole sostituirsi a Quequero per arrivare infine a prendere il posto dell'Eccelso!!! Cambiate strada fino a che siete in tempo!


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.