Pb Hook....

Signaler
Messages postés
7
Date d'inscription
samedi 3 février 2007
Statut
Membre
Dernière intervention
27 août 2011
-
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
-
Bonjour,

J'ai crée une dll très simple appelée "DllMaths.dll", qui contient deux fonctions, "carre" et "cube", je vous laisse deviner ce que ces fonctions me renvoie....

J'ai ensuite crée un exécutable très simple qui calcul le carré d'un nombre en appelant la fonction carré de la dll.

En m'appuyant sur ce code sourcehttp://www.cppfrance.com/codes/SNIFFER-MSN-GRACE-HOOK-FONCTIONS-WINSOCK_32374.aspx, j'ai crée une dll me permettant de hooker l'appel de la fonction "carre", par la fonction cube. Le hook fonction parfaitement si dans le programme calculant les carre, j'utilise le code :

extern "C" __declspec (dllimport) int carre(int x);

Par contre si j'utilise la dll via ce code :

typedef int (WINAPI *DLLfctCarre) (int x);
  HINSTANCE hDLL;
  DLLfctCarre carre;
           .....

hDLL = LoadLibrary(L"DllMaths.dll");
carre = ( DLLfctCarre ) GetProcAddress ( hDLL , "carre" );
           :
le hook ne fonctionne plus....

En gros dans la seconde methode, la dll est chargé dynamiquement non ?
En tous cas dans la seconde méthode "DllMaths.dll" n'apparait pas comme dependance de mon executable dans dependancy walkers....

Ma question, peut on hooker une dll que l'on sait utilisée par un programme, si celle ci est chargée dynamiquement, et si oui, d'ou viens mon erreur ?

Merci.

7 réponses

Messages postés
1107
Date d'inscription
mercredi 15 juin 2011
Statut
Membre
Dernière intervention
10 juillet 2018
4
Tu as essayé en virant le "WINAPI" ? (a moins qu'il soit aussi dans ta dll) :
extern "C" __declspec (dllexport) WINAPI int carre(int x); (je ne sais plus trop où est la position de winapi.)

Entre ton exe et ta dll, une seule chose doit changer dans le proto de la focntion : dllimport/dllexport, tout le reste doit être identique.


Sinon, pour approfondir quel est le pb ?
hDLL est null ? carre est null ?

PS : dans les 2 cas la dll est chargée dynamiquement. Je ne sais pas trop l'expliqué, mais dans le 1er cas le lien est effectué à la "compil" grace au fichier lib (lien statique, mais chargement dynamique).
Messages postés
7
Date d'inscription
samedi 3 février 2007
Statut
Membre
Dernière intervention
27 août 2011

Salut,


Merci pour ta réponse. En fait je sais pas si je me suis bien expliqué,
mais dans les deux cas, mon programme, qui calcul les carrés
fonctionne. L'appel a la fonction "carre" contenue dans la dll
"DllMaths.dll" se fait normalement. Donc ni "hDll", ni "carre" ne son
NULL dans mon exe.


Par contre dans le second cas, le Hook de la fonction carre par mon second programme, ne fonctionne pas.

Dans ma Dll je n'ai pas mis WINAPI, avec mon dllexport.

J'ai cependant essayé de supprimer le WINAPI, cela ne change rien, l'appel de la fonction carre se fait de la meme manière (j'imagine donc que mon WINAPI etait superflu).

J'ai egalement supprimé de ma Dll de hook, les WINAPI et autre __stdcall qui du coup me semblait superflu (extrait des declaration d'entete de ma dll de hook) :

typedef int(*CARRPROC)(int); // prototype fonction carré
typedef int(*CUBEPROC)(int); // prototype fonction cube
                         ...
static int /*__stdcall*/ _carre(int x);  // proto des fonctions
static int /*__stdcall*/ _cube(int x);   // de remplacement

Résultats, exactement la meme chose, le hook fonctionne sur le programme ou la fonction "carre" est importer via "dllimport" et ne fonctionne pas sur celui ou elle est importer via "LoadLibrary()/GetProcAddress()"
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Salut,

Oui bien sûr, comme tu le dis, si tu utilises LoadLibrary/GetProcAdress et que ton hook se base sur la table d'import, celui-ci ne va bien sûr pas fonctionner.

Tu as (Au moins) deux solutions :
1) Hooker GetProcAdress pour renvoyer l'adresse de la fonction "cube" quand on te demande l'adresse de la fonction "carre".
2) Patcher le code de la fonction "carre" (Avec un hook de LoadLibrary par exemple) en mettant en début de celle-ci un saut vers la fonction "cube".
Messages postés
7
Date d'inscription
samedi 3 février 2007
Statut
Membre
Dernière intervention
27 août 2011

Mmmmh interessant, je suis en essai la, pour l'instant, j'ai reussi a hooker LoadLibrary ainsi que GetProcAddress, du coup j'arrive a recupere dans ma dll de hook, le Handle de DllMaths.dll...

Après j'avoue etre un peu bloqué, est ce que je dois crée une autre dll a injecter dans mon programme par la 1ere dll (injecté precedemment), une foi que j'ia recupere ce handle ?

De plus, pour hooker loadlibrary et getprocadress, je suis obligé de lancer le hook avant de lancer l'execution de mon programme. Ceci dit ce n'est pas specialement genant.

Autre question, qu'en est il de la maniere a utiliser si je veux hooker une fonction d'une dll qui est appelé par une dll de mon executable ?

Schema :

Exe , charge Dll_A, pour utiliser fonction_A() contenu dans Dll_A, et Dll_B est chargée par Dll_A, et fonction_A(), fait appel a fonction_B() contenue dans Dll_B, comment intercepter les appels a fonctions B ?

Merci d'avance, pour toute indice sur ces problemes.
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Dans ce cas, je te conseille vivement ma solution 2). En modifiant la fonction elle même, quelque soit la méthode d'appel et qui l'utilise, on la hook toujours.

En améliorant un peu le code suivant, on peut s'arranger pour que la fonction originale reste utilisable (En récupérant les instructions en début de la fonction, et en les exécutant avant de faire un saut pour retourner dans celle-ci.

Pour compiler sous gcc, ajouter -nostartfiles -nodefaultlibs -nostdlib -ffreestanding dans les options du lieur.
Pour compiler sous VC, s'arranger pour que le lieur ignore toutes les librairies par défaut (/nodefaultlib).
<hr size="2" width="100%" />#ifdef UNICODE
#define _UNICODE
#endif /* UNICODE */

#include <windows.h>
#include <tchar.h>

#ifdef UNICODE
#define MSGBOX_FUNC "MessageBoxW"
#else
#define MSGBOX_FUNC "MessageBoxA"
#endif /* UNICODE */

/**
 * Alloue une zone mémoire en utilisant VirtualAlloc
 *
 * @param nSize Taille de la zone à allouer
 * @return Pointeur sur la zone allouée
 */
void* __stdcall Mem_Alloc(DWORD nSize)
{
  return VirtualAlloc(NULL, nSize,
                      MEM_RESERVE | MEM_COMMIT,
                      PAGE_READWRITE);
}

/**
 * Libère une zone mémoire allouée avec Mem_Alloc
 *
 * @param Pointeur sur la zone allouée
 */
void __stdcall Mem_Free(void *lpAddress)
{
  VirtualFree(lpAddress, 0, MEM_RELEASE);
}

/**
 * Affiche un message d'erreur correspondant à la dernière erreur Win32
 */
DWORD __stdcall ShowLastError()
{
  DWORD nLastError;           /* Numéro de l'erreur                           */
  LPTSTR lpMessageBuffer;     /* Récupération du message                      */

  nLastError = GetLastError();

  /* Formatage du message */
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, nLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (void*)&lpMessageBuffer, 0, NULL);

  /* Affichage du message */
  MessageBox(NULL, lpMessageBuffer, _T("ERROR"), MB_OK | MB_ICONERROR);

  LocalFree(lpMessageBuffer);
  return nLastError;
}

/**
 * Affiche le texte indiqué dans la console
 *
 * @param lpText Texte à écrire dans la console
 * @return FALSE en cas de problème
 */
BOOL __stdcall Con_WriteLn(const TCHAR *lpText)
{
  DWORD nWritten;   /* Réception du nombre de caractère écris                 */
  char *lpOemText;  /* Texte traduit en OEM                                   */
  DWORD nSize;      /* Taille du texte à écrire                               */
  BOOL bRes;

  /* Traduction des caractère àùéè... */
  nSize = lstrlen(lpText);

  /* On aura un \n en plus */
  nSize++;

  lpOemText = (char*)Mem_Alloc(nSize);
  CharToOem(lpText, lpOemText);
  lstrcatA(lpOemText, "\n");

  bRes = WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), lpOemText,
                      nSize, &nWritten, NULL);

  Mem_Free(lpOemText);
  return bRes;
}

/**
 * Notre fonction appelée à la place de MessageBox
 */
int __stdcall MyMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, DWORD uType)
{
  Con_WriteLn(lpText);
  return IDOK;
}

int __stdcall InstallHook()
{
  HMODULE hUser32;        /* Handle sur user32.dll                            */
  BYTE *lpWin32MsgBox;    /* Adresse de la fonction win32                     */
  int *lpOffset;          /* Adresse de l'offset du saut                      */
  int nOffset;            /* Distance entre la fonction win32 et la notre     */
  DWORD nOldProtect;      /* Récupération de l'ancienne protection            */
  int nResult;

  nResult = 0;

  /* Chargement de la librairie */
  hUser32 = LoadLibrary(_T("user32.dll"));
  if (! hUser32) goto the_end;

  /* Récupération de l'adresse de la fonction Win32 */
  lpWin32MsgBox = (char*)GetProcAddress(hUser32, MSGBOX_FUNC);
  if (! lpWin32MsgBox) goto free_lib;

  /* Lock de la zone pour la rendre accessible en écriture */
  if (! VirtualProtect(lpWin32MsgBox, 5, PAGE_EXECUTE_READWRITE, &nOldProtect)) goto free_lib;

  /* Ecriture de l'opcode de jmp */
  lpWin32MsgBox[0] = 0xE9;

  /* Calcul du saut, corrigé car eip pointe l'instruction d'après */
  nOffset = (int)&MyMessageBox - (int)(lpWin32MsgBox + 5);

  /* On passe le E9 */
  lpOffset = (int*)&lpWin32MsgBox[1];

  /* Mise en place de l'offset du saut */
  lpOffset[0] = nOffset;

  nResult = 1;

free_lib:
  FreeLibrary(hUser32);
the_end:
  return nResult;
}

/**
 * Main
 */
int __cdecl mainCRTStartup()
{
  int nResult;

  /* Installation du hook */
  if (! InstallHook())
  {
    nResult = ShowLastError();
    goto the_end;
  }

  /* Test du hook */
  MessageBox(0, _T("Foo"), _T("Bar"), MB_OK);

  nResult = 0;
the_end:
  /* ExitProcess nécessaire car sinon c'est un ExitThread */
  ExitProcess(nResult);

  /* Pour esquiver le warning */
  return 0;
}
Messages postés
7
Date d'inscription
samedi 3 février 2007
Statut
Membre
Dernière intervention
27 août 2011

Merci beaucoup pour toute ces pistes, je vais étudier ton code, je suis aussi en train de lire Richter (la partie sur les dll et hook). Je te tiendrais au courant de mes avancées. J'ai neanmoins deja une petite question, le code source que tu ma donné est celui d'une dll, mais du coup je dois l'injecter dans tous les thread si je veux l'utiliser ?
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Le code que je t'ai donné n'est pas celui d'une dll : c'est une application console. L'application hook uniquement ses propres appels.

"je dois l'injecter dans tous les thread" -> Tous les threads d'un même processus vivent dans le même espace mémoire. Ils ont des piles différentes, mais elles vivent dans le même espace. Donc si tu veux hooker pour tous les processus, il faut t'injecter dans tous les processus. Mais ce n'est généralement pas la bonne méthode -> il faut plutôt utilisé un hook d'appel système. Exemple ici.