Winapi bridge

Data

by epokh

�

11/06/2006

UIC's Home Page

Published by Quequero

"Inizia con il piccolo ed il semplice per conseguire il grande ed il complesso"

Grazie epo!

"Tutto ciò che è complesso ha origine dal semplice"
Tao-Teh-Ching,63

....

Home page: http://www.epokh.org
E-mail: [email protected]
skype: matrix.epokh

....

Livello

( )NewBies (X)Intermediate ()Advanced ( )Master

�
�

Introduzione

In questo articolo descrivo la tecnica del bridging delle api.

Tools usati

I soliti tools: OllyDB per il debugging,Visual Studio per creare la DLL, MSDN per la documentazione, PEDitor per esaminare le DLL.

Codice

Il progetto in visual studio è in allegato, il windows replacer è un tool per sostiuire i file di sistema.

Essay

La tecnica dell'api bridge (letteralmente ponte fra api) è utile quando si vogliono hookare parzialmente o totalmente le funzioni presenti nell'interfaccia di una dll. Nel mio caso ho scelto la dll chiamata winscard (potete trovarla in %windows%/%system32%/) che è responsabile della gestione dell'interfaccia smart card <-> computer. La scelta è dovuta al fatto che molti software oramai si affidano alla protezione con smartcard che possono essere di qualsiasi tipo usb-token, contact less o di tipo card. Il recente vygiss, un programma per sbloccare le schede 3 dei cellulari, usava proprio questa protezione ed è stato sprotetto proprio con questa tecnica.
Per completezza di esposizione, è necessario esaminare i concetti principali sulle DLL:

Overview sulle DLL
Una DLL (dynamic-link library) è un modulo che contiene funzioni e dati che possono essere usati da un altro modulo (applicazione o DLL) .
Una dll può definire 2 tipi di funzioni: esportate ed interne. Le funzioni esportate sono quelle che verranno chiamate dagli altri moduli, ma anche dalle stesse funzioni definite nella DLL. Le funzioni interne sono invece chiamate solo internamente dalla DLL. Sebbene una DLL possa esportare dati, i suoi dati sono generalmente usati solo dalle sue funzioni. Comunque, non si può far nulla per evitare che un modulo legga o scriva i corrispondenti indirizzi in memoria.

Il linking dinamico e statico
Il linking dinamico consente ad un modulo di includere solo le informazioni necessarie per trovare una funzione esportata dalla DLL a load time o run time. Il linking dinamico differisce dal linking statico, nel quale il linker copia il codice delle funzioni della libreria in ogni modulo chiamante.
Tipi di linking dinamico:
Esistono 2 metodi per chiamare una funzione in una DLL:

Le DLL e la gestione della memoria

Ogni processo che carica una DLL, mappa lo spazio di indirizzamento della DLL nel suo. Dopo che il processo carica la DLL nel suo spazio di indirizzamento virtuale, esso può chiamare le funzioni esportate dalla DLL.
Il sistema mantiene un contatore di riferimento per ogni DLL. Quando un thread carica la DLL, il contatore di riferimento viene incrementato di uno. Quando il processo termina, o quando il contatore diventa zero(solo nel caso di linking dinamico), la DLL è deallocata dallo spazio di indirizzamento virtuale del processo.
Come ogni altra funzione, una funzione esportata da una DLL runna nel contesto del thread chiamante. Quindi, si applicano le seguenti condizioni:


Il nostro caso di studio (winscard.dll) è quello del linking dinamico sopra citato. Possiamo schematizzare il nostro approccio come in figura:



La fake dll è quella che dovremo sviluppare noi, mentre la dll originale è la winscard.dll in %windows%/%system32%.
Cosa farà il programma chiamante? Per prima cosa caricherà la DLL con la funzione LoadLibrary, poi recupererà tutti i puntatori a funzione dell'interfaccia winscard che gli servono: in genere non tutti, ma solo quelli necessari.

Nell'esempio di codice riportato, il programma carica la libreria e poi recupera il puntatore a funzione della funzione SCardEstablishContext:

//Definizioni dei tipi di puntatori alle funzioni della DLL originale

typedef LONG (WINAPI *PSCardEstablishContext)(DWORD dwScope,LPCVOID pvReserved1,LPCVOID pvReserved2,
LPSCARDCONTEXT phContext);

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
{ HINSTANCE hDll;
{ bool check=false;
//Carica la libreria
if( !(hDll = LoadLibrary( "winscardbridge.dll" )) ) {
return MessageBox(NULL,"Errore: impossibile caricare la DLL ","NO",MB_OK);
}
//recupera il puntatore a funzione

PSCardEstablishContext mySCardEstablishContext= (PSCardEstablishContext)GetProcAddress( hDll, "SCardEstablishContext" );


Nel framework che vi presento ho implementato tutta l'interfaccia della winscard.dll in modo che, l'utente deve solo implementare le operazioni da fare nella funzione hookata. La funzioni esportate definite in winscardbridge.def sono le seguenti:


LIBRARY winscardbridge
EXPORTS
SCardEstablishContext
SCardReleaseContext
SCardReconnect
SCardConnectA
SCardDisconnect
SCardTransmit
SCardStatusA
SCardBeginTransaction
SCardEndTransaction
SCardListReadersA
SCardListCardsA
SCardGetStatusChangeA
SCardLocateCardsA
SCardControl
SCardGetAttrib
SCardSetAttrib
SCardFreeMemory
SCardCancel
SCardListReaderGroupsA
SCardIntroduceReaderA
SCardAddReaderToGroupA
SCardRemoveReaderFromGroupA
SCardForgetReaderA
SCardIntroduceReaderGroupA
SCardForgetReaderGroupA
SCardIntroduceCardTypeA
SCardState

Ho riportato una breve descrizione dell'interfaccia della winscard, basata sulla documentazione MSDN:

Smart Card Database Query Functions

 

SCardListReaders

searches the smart card database and provides a list of named cards previously introduced to the system by the user.

SCardListCards

provides the list of readers within a set of named reader groups, eliminating duplicates.

Resource Manager Context Functions

 

SCardEstablishContext

Open a session with the resource manager

SCardReleaseContext

Close the session with the resource manager

Smart Card and Reader Access Functions

 

SCardConnect

establishes a connection (using a specific resource manager context) between the calling application and a smart card contained by a specific reader. If no card exists in the specified reader, an error is returned.

SCardReconnect

reestablishes an existing connection between the calling application and a smart card. This function moves a card handle from direct access to general access, or acknowledges and clears an error condition that is preventing further access to the card.

SCardDisconnect

terminates a connection previously opened between the calling application and a smart card in the target reader.

SCardStatus

provides the current status of a smart card in a reader. You can call it any time after a successful call to SCardConnect and before a successful call to SCardDisconnect. It does not affect the state of the reader or reader driver.

SCardBeginTransaction

starts a transaction, waiting for the completion of all other transactions before it begins.

When the transaction starts, all other applications are blocked from accessing the smart card while the transaction is in progress.

SCardEndTransaction

completes a previously declared transaction, allowing other applications to resume interactions with the card.

SCardTransmit

sends a service request to the smart card and expects to receive data back from the card.

Smart Card Tracking Functions

 

SCardLocateCards

searches the readers listed in the rgReaderStates parameter for a card with an ATR string that matches one of the card names specified in mszCards, returning immediately with the result.

SCardGetStatusChange

blocks execution until the current availability of the cards in a specific set of readers changes.

Direct Card Access Functions

 

SCardControl

gives you direct control of the reader. You can call it any time after a successful call to SCardConnect and before a successful call to SCardDisconnect

SCardGetAttrib

gets the current reader attributes for the given handle. It does not affect the state of the reader, driver, or card.

SCardSetAttrib

sets the given reader attribute for the given handle. It does not affect the state of the reader, reader driver, or smart card

 
 

Quando si crea una DLL è importante definire il DLLMain (sebbene esso sia opzionale!), che viene chiamata dal sistema quando i processi ed i threads sono inizializzaati e terminati, oppure quando il thread chiamante fa LoadLibrary o FreeLibrary.



Il parametro ul_reason_for_call ci permette di capire se la DLL è caricata\scaricata da un processo\thread, essa può assumere i corrispondenti valori:DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,DLL_THREAD_ATTACH,DLL_THREAD_DETACH con gli ovvi significati.

MyDLLInit
In questa funzione inizializziamo la nostra DLL.
Costruiamo il path assoluto della dll originale del tipo c:\windows\system32\winscard.dll, facciamo il load della dll in questione,recupera tutti i puntatori a funzione dell'interfaccia ed apre un file di log. Vediamo alcune porzioni di codice relative:

//definiamo i tipi puntatori a funzione con le signature corrette
typedef LONG (WINAPI *pSCardEstablishContext)(DWORD,LPCVOID,LPCVOID,LPSCARDCONTEXT);
typedef LONG (WINAPI *pSCardReleaseContext)(SCARDCONTEXT);
//definisco
i puntatori alle funzioni della dll originale (interne alla mia fake dll)
pSCardEstablishContext MySCardEstablishContext;
pSCardReleaseContext MySCardReleaseContext;

//definisco le funzioni di interfaccia della mia fake dll
LONG WINAPI SCardEstablishContext(DWORD,LPCVOID,LPCVOID,LPSCARDCONTEXT);
LONG WINAPI SCardReleaseContext(SCARDCONTEXT);


Le signature dell'interfaccia sono state riprese dalla MSDN. Stiamo attenti a non confonderci: la nostra fake dll espone le stesse funzioni, con stesso prototipo e stessi nomi della dll originale. L'hooking si effettua all'interno della le funzioni della nostra fake dll.
Per le funzioni che non vogliamo hookare richiamiamo semplicemente la funzione della dll originale mediante i puntatori recuperati durante l'init, mentre per quelle che vogliamo hookare, prima della chiamata alla funzione originale, effettuiamo il nostro payload.
Il recupero dei puntatori avviene nel modo seguente:
//definiamo i tipi puntatori a funzione con le signature corrette
typedef LONG (WINAPI *pSCardEstablishContext)(DWORD,LPCVOID,LPCVOID,LPSCARDCONTEXT);
//get the system path
char systempath[MAX_PATH];
if(GetSystemDirectory(systempath,MAX_PATH+1)==0) return FALSE;
char originaldll[]="\\winscard.dll";
char *totalpath=lstrcat(systempath,originaldll);
if( !hDll) {
return FALSE;
}
else
{
//open the log file
fstreamLog = fopen( "winscard.log", "a+" );
//recover the function pointer of the original DLL
if(fstreamLog!=NULL) OutputDebugString("Log file created!");
else return false;
//notiamo gli opportuni operatori di casting
MySCardEstablishContext = (pSCardEstablishContext)GetProcAddress( hDll, "SCardEstablishContext" );
if( !MySCardEstablishContext ) return FALSE;
MySCardReleaseContext = (pSCardReleaseContext)GetProcAddress( hDll, "SCardReleaseContext" );
if( !MySCardReleaseContext ) return FALSE;
 

Ecco un esempio: non vogliamo hookare la EstablishContext e ReleaseContext, mentre vogliamo hookare la SCardTransmit.

//definiamo i tipi puntatori a funzione con le signature corrette
LONG WINAPI SCardEstablishContext( DWORD dwScope,LPCVOID pvReserved1,LPCVOID pvReserved2,LPSCARDCONTEXT phContext)
{
//chiamiamo la funzione della dll originale
return MySCardEstablishContext(dwScope,pvReserved1,pvReserved2,phContext);
}

LONG WINAPI SCardReleaseContext(SCARDCONTEXT hContext)
{
//qui lo stesso
return MySCardReleaseContext(hContext);
}

//mentre vogliamo loggare il traffico dati relativo alla SCardTransmit
LONG WINAPI SCardTransmit(SCARDHANDLE hCard,LPCSCARD_IO_REQUEST pioSendPci,LPCBYTE pbSendBuffer,DWORD cbSendLength,
LPSCARD_IO_REQUEST pioRecvPci,
LPBYTE pbRecvBuffer,
LPDWORD pcbRecvLength
)
{
//qui logga i dati scambiat fra l'host pc e la smart card in full duplex
logScardTrasmit(pbSendBuffer,cbSendLength,pbRecvBuffer,*pcbRecvLength);
return MySCardTransmit(hCard,pioSendPci,pbSendBuffer,cbSendLength,pioRecvPci,pbRecvBuffer,pcbRecvLength);
}

MyDllUnload
Questa funzione viene chiamata quando viene fatto l'unload della nostra dll. Nel nostro caso è necessario liberare a sua volta la memoria associata alla dll originale caricata in precedenza e chiudere il file di log precedentemente aperto.


BOOL MyDllUnload()
{
fclose(fstreamLog);
OutputDebugString("Log file closed!");
//hDllInstance è l'handle della dll originale caricata
return FreeLibrary(hDllInstance);
}

Uso del framework
Il framework può essere usato per emulare una smartcard (quindi anche le dongle che rientrano in questa categoria).
Come si fa? Supponendo di avere la smart card, prima registriamo tutto il traffico dati tra l'host e la card, e poi scriviamo un emulatore, sempre come fake dll che alle request dell'host risponde con le answer precedentemente acquisite. Ovviamente se il software usa una smart card, con caratteristiche di crittografia, un challenge response sulle chiavi o uno scambio mediante crittografia asimettrica, manda all'aria il nostro sistema.
D'altra parte, i software visti finora usano delle dongle banali, ma questo non esclude che in futuro o tuttora si usino delle smart card più intelligenti.
Un altra cosa a cui dobbiamo stare attenti, è come viene caricata la da parte dell'eseguibile.
Infatti se esso fa una cosa del tipo: LoadLibrary("nomedll.dll"), siamo a cavallo perchè basta mettere la nostra dll nello stesso path dell'exe. Tuttavia i programmatori si sono iniziati ad infurbire ed iniziano a mettere i path assoluti nelle LoadLibrary, quindi in quel caso dobbiamo rinominare la dll originale e mettere quella fake nella cartella di system32. Poichè windows non permette questa operazione, dobbiamo usare un tool come windows replacer.
 
 
�
 
���������������������������������������������������������������������������������������������������������������� ..::EPOKH::..

Final notes

Le smart card sono il bene! Spero che prima o poi sostituiscano tutte le carte di credito con chip smart. Non se ne può più con le carte a banda magnetica! Le clonano in un attimo!

Disclaimer

Vorrei ricordare che il software va comprato e� non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento � stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo che ogni sviluppatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.

Reversiamo al solo scopo informativo e per migliorare la nostra conoscenza del linguaggio Assembly.�