Strana gente!
(puntatori a funzione e registry)

Data

by "syscalo"

 

12/04/2001

UIC's Home Page

Published by Quequero


Syscalo come sempre è precissimo e chiaro, ma perchè non mi mandi qualche tutorial in più???

 

....

Home page: http://syscalo.cjb.net
E-mail: x4sys@iname.com

....

Difficoltà

(x)NewBies ( )Intermedio ( )Avanzato ( )Master

 

Volete sapere cosa stò facendo? Continuate a leggere ;-p


Strana gente!
(puntatori a funzione e registry)
Written by syscalo

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 usati

Ida, giusto per disassemblare.

URL o FTP del programma

Eccolo qua ;-)

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 

#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 e' 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 e' 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 e' dho, ma la stringa e' 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

Qualunque azione punitiva del mio caro amico AndreaGeddon (ciao Andreuzzo ;-p) nei miei confronti è da considerarsi come conferma delle mie affermazioni.
Quindi andrea se non vuoi che l'Eccelso se la prenda con te non puoi farmi niente hihihi