begin process at 2012 05 27 19:23:31
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

API

 > SOUS-CLASSEMENT DE FENÊTRE D'UN AUTRE PROCESS PAR INJECTION DLL

SOUS-CLASSEMENT DE FENÊTRE D'UN AUTRE PROCESS PAR INJECTION DLL


 Information sur la source

Note :
10 / 10 - par 1 personne
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :API Classé sous :Injection, Dll, Sous-Classement, Fenêtre, CreateRemoteThread Niveau :Débutant Date de création :15/06/2010 Vu / téléchargé :2 897 / 151

Auteur : racpp

Ecrire un message privé
Commentaire sur cette source (11)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Voici un code source montrant comment sous-classer une fenêtre appartenant à un autre process. La technique de l'injection de code par dll est utilisée. Le but de ce sous-classement est de pouvoir intercepter les messages destinés à n'importe quelle fenêtre cible afin de les traiter de manière personnalisée.
L'injecteur est sous forme de boite de dialogue disposant d'un combobox qui contiendra les noms de toutes les fenêtres visibles à l'écran. Le bouton "Injecter" permet d'injecter et exécuter le code de notre dll dans le process de la fenêtre choisie. Le HWND de cette dernière est transmis via le presse-papier au DllMain de notre dll en utilisant un format privé. Un bouton "Actualiser" permet de rafraichir le contenu du combobox.
La dll contient deux fonctions: Le DllMain et notre procédure de sous-classement. Dans le DllMain, l'adresse de la procédure originale de la fenêtre à sous-classer est sauvegardée dans une propriété assignée pour l'occasion à cette fenêtre grâce à SetProp(). GetProp() permet de retrouver cette adresse originale dans la procédure de sous-classement afin d'y aiguiller les messages qu'on ne désire pas traiter. Ainsi, chaque fenêtre retrouve sa propre procédure originale si le message qui lui parvient n'est pas capturé par notre procédure de sous-classement. Dans cet exemple, le message WM_SYSCOMMAND dont wParam vaut SC_CLOSE est intercepté pour afficher un petit message prouvant que le sous-classement est effectif chaque fois qu'on décide de fermer la fenêtre sous-classée. Libre à vous de modifier le code pour traiter les messages que vous voulez.
Ce code source se compose de deux projets: celui de l'injecteur et celui de la dll. Cette dernière est incluse en ressource binaire de l'exécutable injecteur qui l'extrait dans son dossier s'il ne la trouve pas.
Les deux petits projets ont été faits sous Visual C/C++ 2005 et sont facilement adaptables. Celui de la dll est en pur C.
Il est à noter que par souci de clarté du code source, généralement les valeurs de retour des fonctions ne sont pas traitées.
Pour tester l'injecteur, renommez-le en Injecteur.exe. Des tests ont été faits sans aucun problème sur Windows XP, Vista et 7.
Voilà, j'espère n'avoir rien oublié.
Toutes les remarques, questions et commentaires sont les bienvenus.

Source

  • //********************** Code de l'injecteur **********************
  • #include <windows.h>
  • DWORD Inject(HWND hwndclipboard, HWND hwndcible)
  • {
  • char dllpath[MAX_PATH];
  • // Obtenir le chemin complet de notre exécutable:
  • GetModuleFileName(0,dllpath,MAX_PATH);
  • // Remplacer le nom de l'exécutable par le nom de la dll:
  • lstrcpy(strrchr(dllpath,'\\')+1,"wndprocdll.dll");
  • // Vérifier l'existence de la dll dans le dossier de l'exe:
  • DWORD attrib=GetFileAttributes(dllpath);
  • // Extraire la dll depuis les ressouces de l'exe si elle n'existe pas:
  • if(attrib==INVALID_FILE_ATTRIBUTES)
  • {
  • // Trouver la ressource:
  • HRSRC hbinresource=FindResource(0,"IDB_DLL","BINARY");
  • // Déterminer sa taille:
  • DWORD dwtaille=SizeofResource(0,hbinresource);
  • // Charger la ressource en mémoire:
  • HGLOBAL hResource=LoadResource(0,hbinresource);
  • // Obtenir un pointeur sur cette zone mémoire:
  • char* pbuf=(char*)LockResource(hResource);
  • // Créer le fichier destination:
  • HANDLE hFichier=CreateFile(dllpath,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
  • // S'assurer que le fichier a bien été créé:
  • if(hFichier!=INVALID_HANDLE_VALUE)
  • {
  • // Copier la ressource dans le fichier:
  • DWORD dwecrits;
  • WriteFile(hFichier,pbuf,dwtaille,&dwecrits,0);
  • // Fermer le fichier:
  • CloseHandle(hFichier);
  • }
  • // Libérer la ressource:
  • UnlockResource(hResource);
  • FreeResource (hResource);
  • }
  • // Obtenir l'identificateur du process auquel appartient la fenêtre:
  • DWORD dwpid;
  • DWORD threadid=GetWindowThreadProcessId(hwndcible,&dwpid);
  • // Ouvrir ce process:
  • HANDLE hProcess=OpenProcess( PROCESS_ALL_ACCESS, 0,dwpid);
  • // Obtenir la longueur du chemin complet de notre dll:
  • DWORD dwpathlen=lstrlen(dllpath);
  • // Allouer de la mémoire dans ce process pour y stocker le chemin de notre dll:
  • char* pmem=(char*)VirtualAllocEx(hProcess,0,dwpathlen+1,MEM_COMMIT,PAGE_READWRITE);
  • // Copier le chemin de notre dll vers la mémoire allouée dans le process cible:
  • BOOL bret=WriteProcessMemory(hProcess,(LPVOID) pmem,(LPVOID) dllpath, dwpathlen+1, NULL);
  • // Obtenir le HMODULE de kernel32.dll:
  • HMODULE hkernel32=GetModuleHandle("Kernel32");
  • // Obtenir l'adresse de la fonction LoadLibraryA de kernel32.dll:
  • PTHREAD_START_ROUTINE pfnThreadRtn=(PTHREAD_START_ROUTINE)GetProcAddress(hkernel32, "LoadLibraryA");
  • // Ouvrir le presse-papier:
  • OpenClipboard(hwndclipboard);
  • // Mettre le HWND de la fenêtre cible dans le presse-papier:
  • SetClipboardData(CF_PRIVATEFIRST ,hwndcible);// Format privé
  • // Fermer le presse-papier:
  • CloseClipboard();
  • // Créer et lancer un thread distant dans le process cible:
  • HANDLE hThread= CreateRemoteThread(hProcess, NULL, 0,pfnThreadRtn, pmem, 0, NULL);
  • // Attendre que le thread soit terminé:
  • WaitForSingleObject(hThread, INFINITE);
  • // Libérer la mémoire allouée précédemment:
  • VirtualFreeEx(hProcess, pmem, 0, MEM_RELEASE);
  • // Fermer les handles:
  • CloseHandle(hThread);
  • CloseHandle(hProcess);
  • return 0;
  • }
  • // Procédure d'énumération des fenêtres et de remplissage du combobox:
  • BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
  • {
  • static char buffer[MAX_PATH];
  • // S'assurer que la fenêtre est visible:
  • if(IsWindowVisible(hwnd))
  • {
  • // Récupérer le HWND de notre combobox depuis lParam:
  • HWND hCombo=(HWND)lParam;
  • // S'assurer que la fenêtre a un titre et qu'il ne s'agit pas de celle de notre injecteur:
  • if(GetWindowTextLength(hwnd) && hwnd!=GetParent(hCombo))
  • {
  • // Obtenir le nom de la classe de fenêtre:
  • GetClassName(hwnd,buffer,MAX_PATH);
  • // S'assurer que le nom de classe est différent de "progman":
  • if(lstrcmpi(buffer,"progman"))
  • {
  • // Obtenir le texte du titre de la fenêtre:
  • GetWindowText(hwnd,buffer,MAX_PATH);
  • // Ajouter ce texte comme élément au combobox:
  • SendMessage(hCombo,CB_INSERTSTRING,0,(LPARAM)buffer);
  • // Mettre le HWND de la fenêtre comme valeur associée à l'élément:
  • SendMessage(hCombo,CB_SETITEMDATA,0,(LPARAM)hwnd);
  • }
  • }
  • }
  • return TRUE;
  • }
  • // Procédure de notre boite de dialogue:
  • BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  • {
  • static HWND hCombo,hFermer,hInjecter,hActualiser;
  • switch(message)
  • {
  • case WM_INITDIALOG:
  • {
  • // Définir le titre de notre boite de dialogue:
  • SetWindowText(hwnd,"Injecteur");
  • // Créer les contrôles:
  • CreateWindowEx(0,"static","Liste des fenêtres :",WS_CHILD | WS_VISIBLE,20,10,360,20,hwnd,0,0,0);
  • hCombo=CreateWindowEx(0,"combobox",0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,20,28,360,150,hwnd,0,0,0);
  • hActualiser=CreateWindowEx(0,"button","Actualiser",WS_CHILD | WS_VISIBLE ,20,170,80,20,hwnd,0,0,0);
  • hInjecter=CreateWindowEx(0,"button","Injecter",WS_CHILD | WS_VISIBLE | WS_DISABLED ,160,170,80,20,hwnd,0,0,0);
  • hFermer=CreateWindowEx(0,"button","Fermer",WS_CHILD | WS_VISIBLE ,300,170,80,20,hwnd,0,0,0);
  • // Enumérer les fenêtres en remplissant le combobox:
  • EnumWindows(EnumWindowsProc,(LPARAM)hCombo);
  • // Obtenir la police par défaut des boites de dialogue:
  • HFONT hguifont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
  • // Appliquer cette police à nos contrôles:
  • HWND child=0;
  • while(child=FindWindowEx(hwnd,child,0,0))SendMessage(child,WM_SETFONT,(WPARAM)hguifont,0);
  • }
  • break;
  • case WM_COMMAND:
  • // Dégriser le bouton "Injecter" si un élément du combobox a été sélectionné:
  • if(HIWORD(wParam)==CBN_SELENDOK) EnableWindow(hInjecter,1);
  • // Clic sur "Injecter":
  • if((HWND)lParam==hInjecter)
  • {
  • // Obtenir l'index de la séléction courante du combobox:
  • int cursel=(int)SendMessage(hCombo,CB_GETCURSEL,0,0);
  • // Récupérer le HWND associé comme valeur à l'élément sélectionné:
  • HWND hwndcible=(HWND)SendMessage(hCombo,CB_GETITEMDATA,cursel,0);
  • // S'assurer que la fenêtre n'a pas déjà été sous-classée:
  • if(GetProp(hwndcible,"PROP_WNDPROC"))
  • {
  • MessageBox(hwnd,"La fenêtre choisie a déjà été sous-classée.","Injecteur",0);
  • return 0;
  • }
  • // Lancer la fonction d'injection si la fenêtre est valide:
  • if(IsWindow(hwndcible))Inject(hwnd,hwndcible);
  • // Sinon afficher un message indiquant que le HWND n'est pas valide:
  • else MessageBox(hwnd,"Le HWND de la fenêtre choisie n'est plus valide.","Injecteur",0);
  • return 0;
  • }
  • // Clic sur "Actualier":
  • if((HWND)lParam==hActualiser)
  • {
  • // Vider le combobox:
  • SendMessage(hCombo,CB_RESETCONTENT,0,0);
  • // Griser le bouton "Injecter":
  • EnableWindow(hInjecter,0);
  • // Enumérer les fenêtres en remplissant le combobox:
  • EnumWindows(EnumWindowsProc,(LPARAM)hCombo);
  • return 0;
  • }
  • // Fermer la boite de dialogue si clic sur "Fermer":
  • if((HWND)lParam==hFermer)SendMessage(hwnd,WM_CLOSE,0,0);
  • break;
  • case WM_CLOSE:
  • // Détruire la boite de dialogue:
  • EndDialog(hwnd,0);
  • break;
  • default:
  • break;
  • }
  • return 0;
  • }
  • int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR szcmd, int ishow)
  • {
  • // Allouer de la mémoire pour notre DIALOG TEMPLATE:
  • LPDLGTEMPLATE lpdt=(LPDLGTEMPLATE)GlobalAlloc(GPTR,512);
  • // Définir les dimensions de notre boite dedialogue:
  • lpdt->cx=200; lpdt->cy=100;
  • // Définir les styles de notre boite de dialogue:
  • lpdt->style=DS_CENTER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
  • // Lancer notre boite de dialogue:
  • DialogBoxIndirectParam(GetModuleHandle(0),lpdt,0,(DLGPROC)DlgProc,0);
  • // Libérer la mémoire allouée pour notre DIALOG TEMPLATE:
  • GlobalFree(lpdt);
  • return 0;
  • }
  • //***********************************************************************
  • //*********************** Code de la DLL ********************************
  • #include <windows.h>
  • // Notre procédure de sous-classement:
  • LRESULT CALLBACK MyWndProc(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam)
  • {
  • WNDPROC OldWndProc;
  • // Récupérer l'adresse de la procédure originale depuis la propriété "PROP_WNDPROC" assignée à la fenêtre:
  • OldWndProc=(WNDPROC)GetProp(hwnd,"PROP_WNDPROC");
  • switch(message)
  • {
  • case WM_SYSCOMMAND:
  • if(wParam==SC_CLOSE)
  • {
  • // Afficher le message prouvant le sous-classement de la fenêtre:
  • MessageBox(hwnd,"Ce message prouve que la fenêtre a bien été sous-classée.","Sous-Classement par injection de code.",0);
  • }
  • break;
  • case WM_NCDESTROY:
  • // Retirer la propriété "PROP_WNDPROC" préalablement assignée à la fenêtre sous-classée:
  • RemoveProp(hwnd,"PROP_WNDPROC");
  • break;
  • default:
  • break;
  • }
  • // Appeler la procédure originale:
  • return CallWindowProc(OldWndProc,hwnd,message,wParam, lParam);
  • }
  • // La fonction d'entrée DllMain:
  • int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  • {
  • if (dwReason == DLL_PROCESS_ATTACH)
  • {
  • HWND hwnd;
  • // Ouvrir le presse-papier:
  • OpenClipboard(0);
  • // récupérer le HWND de la fenêtre cible transmis par le programme injetceur:
  • hwnd=(HWND)GetClipboardData(CF_PRIVATEFIRST);
  • // Fermer le presse-papier:
  • CloseClipboard();
  • // S'assurer que le HWND est valide et que la propriété "PROP_WNDPROC" ne lui est pas assignée:
  • if(IsWindow(hwnd) && !GetProp(hwnd,"PROP_WNDPROC"))
  • {
  • WNDPROC OldWndProc;
  • // Récupérer l'adresse de la procédure originale de la fenêtre cible:
  • OldWndProc=(WNDPROC)GetWindowLong(hwnd,GWL_WNDPROC);
  • //Sauvegarder cette adresse dans la propriété "PROP_WNDPROC" à assigner à la fenêtre:
  • SetProp(hwnd,"PROP_WNDPROC",(HANDLE)OldWndProc);
  • // Remplacer la procédure originale par la notre:
  • SetWindowLong(hwnd, GWLP_WNDPROC, (LONG)MyWndProc);
  • }
  • }
  • return 1;
  • }
  • //**********************************************************************
//********************** Code de l'injecteur **********************
#include <windows.h>

DWORD Inject(HWND hwndclipboard, HWND hwndcible)
{
	char dllpath[MAX_PATH];
	// Obtenir le chemin complet de notre exécutable:
	GetModuleFileName(0,dllpath,MAX_PATH);
	// Remplacer le nom de l'exécutable par le nom de la dll:
	lstrcpy(strrchr(dllpath,'\\')+1,"wndprocdll.dll");
	// Vérifier l'existence de la dll dans le dossier de l'exe:
	DWORD attrib=GetFileAttributes(dllpath);
	// Extraire la dll depuis les ressouces de l'exe si elle n'existe pas:
	if(attrib==INVALID_FILE_ATTRIBUTES)
	{
		// Trouver la ressource:
		HRSRC hbinresource=FindResource(0,"IDB_DLL","BINARY");
		// Déterminer sa taille:
		DWORD dwtaille=SizeofResource(0,hbinresource);
		// Charger la ressource en mémoire:
		HGLOBAL hResource=LoadResource(0,hbinresource);
		// Obtenir un pointeur sur cette zone mémoire:
		char* pbuf=(char*)LockResource(hResource);
		// Créer le fichier destination:
		HANDLE hFichier=CreateFile(dllpath,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
		// S'assurer que le fichier a bien été créé:
		if(hFichier!=INVALID_HANDLE_VALUE)
		{
			// Copier la ressource dans le fichier:
			DWORD dwecrits;
			WriteFile(hFichier,pbuf,dwtaille,&dwecrits,0);
			// Fermer le fichier:
			CloseHandle(hFichier);
		}
		// Libérer la ressource:
		UnlockResource(hResource);
		FreeResource (hResource);
	}
	// Obtenir l'identificateur du process auquel appartient la fenêtre:
	DWORD dwpid;
	DWORD threadid=GetWindowThreadProcessId(hwndcible,&dwpid);
	// Ouvrir ce process:
	HANDLE hProcess=OpenProcess( PROCESS_ALL_ACCESS, 0,dwpid);
	// Obtenir la longueur du chemin complet de notre dll:
	DWORD dwpathlen=lstrlen(dllpath);
	// Allouer de la mémoire dans ce process pour y stocker le chemin de notre dll:
	char* pmem=(char*)VirtualAllocEx(hProcess,0,dwpathlen+1,MEM_COMMIT,PAGE_READWRITE);
	// Copier le chemin de notre dll vers la mémoire allouée dans le process cible:
	BOOL bret=WriteProcessMemory(hProcess,(LPVOID) pmem,(LPVOID) dllpath, dwpathlen+1, NULL);
	// Obtenir le HMODULE de kernel32.dll:
	HMODULE hkernel32=GetModuleHandle("Kernel32");
	// Obtenir l'adresse de la fonction LoadLibraryA de kernel32.dll:
	PTHREAD_START_ROUTINE pfnThreadRtn=(PTHREAD_START_ROUTINE)GetProcAddress(hkernel32, "LoadLibraryA");
	// Ouvrir le presse-papier:
	OpenClipboard(hwndclipboard);
	// Mettre le HWND de la fenêtre cible dans le presse-papier:
	SetClipboardData(CF_PRIVATEFIRST ,hwndcible);// Format privé
	// Fermer le presse-papier:
	CloseClipboard();
	// Créer et lancer un thread distant dans le process cible:
	HANDLE hThread= CreateRemoteThread(hProcess, NULL, 0,pfnThreadRtn, pmem, 0, NULL);
	// Attendre que le thread soit terminé:
	WaitForSingleObject(hThread, INFINITE);
	// Libérer la mémoire allouée précédemment:
	VirtualFreeEx(hProcess, pmem, 0, MEM_RELEASE);
	// Fermer les handles:
	CloseHandle(hThread);
	CloseHandle(hProcess);
	return 0;
}

// Procédure d'énumération des fenêtres et de remplissage du combobox:
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
{
	static		char buffer[MAX_PATH];
	// S'assurer que la fenêtre est visible:
	if(IsWindowVisible(hwnd))
	{
		// Récupérer le HWND de notre combobox depuis lParam:
		HWND hCombo=(HWND)lParam;
		// S'assurer que la fenêtre a un titre et qu'il ne s'agit pas de celle de notre injecteur:
		if(GetWindowTextLength(hwnd) && hwnd!=GetParent(hCombo))
		{
			// Obtenir le nom de la classe de fenêtre:
			GetClassName(hwnd,buffer,MAX_PATH);
			// S'assurer que le nom de classe est différent de "progman":
			if(lstrcmpi(buffer,"progman"))
			{
				// Obtenir le texte du titre de la fenêtre:
				GetWindowText(hwnd,buffer,MAX_PATH);
				// Ajouter ce texte comme élément au combobox:
				SendMessage(hCombo,CB_INSERTSTRING,0,(LPARAM)buffer);
				// Mettre le HWND de la fenêtre comme valeur associée à l'élément:
				SendMessage(hCombo,CB_SETITEMDATA,0,(LPARAM)hwnd);
			}
		}
	}
	return TRUE;
}

// Procédure de notre boite de dialogue:
BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hCombo,hFermer,hInjecter,hActualiser;
	switch(message)
	{

	case WM_INITDIALOG:
		{
			// Définir le titre de notre boite de dialogue:
			SetWindowText(hwnd,"Injecteur");
			// Créer les contrôles:
			CreateWindowEx(0,"static","Liste des fenêtres :",WS_CHILD | WS_VISIBLE,20,10,360,20,hwnd,0,0,0);
			hCombo=CreateWindowEx(0,"combobox",0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,20,28,360,150,hwnd,0,0,0);
			hActualiser=CreateWindowEx(0,"button","Actualiser",WS_CHILD | WS_VISIBLE ,20,170,80,20,hwnd,0,0,0);
			hInjecter=CreateWindowEx(0,"button","Injecter",WS_CHILD | WS_VISIBLE | WS_DISABLED ,160,170,80,20,hwnd,0,0,0);
			hFermer=CreateWindowEx(0,"button","Fermer",WS_CHILD | WS_VISIBLE ,300,170,80,20,hwnd,0,0,0);
			// Enumérer les fenêtres en remplissant le combobox:
			EnumWindows(EnumWindowsProc,(LPARAM)hCombo);
			// Obtenir la police par défaut des boites de dialogue:
			HFONT hguifont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
			// Appliquer cette police à nos contrôles:
			HWND child=0;
			while(child=FindWindowEx(hwnd,child,0,0))SendMessage(child,WM_SETFONT,(WPARAM)hguifont,0);
		}
		break;

	case WM_COMMAND:
		// Dégriser le bouton "Injecter" si un élément du combobox a été sélectionné:
		if(HIWORD(wParam)==CBN_SELENDOK) EnableWindow(hInjecter,1);
		// Clic sur "Injecter":
		if((HWND)lParam==hInjecter)
		{
			// Obtenir l'index de la séléction courante du combobox:
			int cursel=(int)SendMessage(hCombo,CB_GETCURSEL,0,0);
			// Récupérer le HWND associé comme valeur à l'élément sélectionné:
			HWND hwndcible=(HWND)SendMessage(hCombo,CB_GETITEMDATA,cursel,0);
			// S'assurer que la fenêtre n'a pas déjà été sous-classée:
			if(GetProp(hwndcible,"PROP_WNDPROC"))
			{
				MessageBox(hwnd,"La fenêtre choisie a déjà été sous-classée.","Injecteur",0);
				return 0;
			}
			// Lancer la fonction d'injection si la fenêtre est valide:
			if(IsWindow(hwndcible))Inject(hwnd,hwndcible);
			// Sinon afficher un message indiquant que le HWND n'est pas valide:
			else MessageBox(hwnd,"Le HWND de la fenêtre choisie n'est plus valide.","Injecteur",0);	
			return 0;
		}
		// Clic sur "Actualier":
		if((HWND)lParam==hActualiser)
		{
			// Vider le combobox:
			SendMessage(hCombo,CB_RESETCONTENT,0,0);
			// Griser le bouton "Injecter":
			EnableWindow(hInjecter,0);
			// Enumérer les fenêtres en remplissant le combobox:
			EnumWindows(EnumWindowsProc,(LPARAM)hCombo);
			return 0;
		}
		// Fermer la boite de dialogue si clic sur "Fermer":
		if((HWND)lParam==hFermer)SendMessage(hwnd,WM_CLOSE,0,0);
		break;

	case WM_CLOSE:
		// Détruire la boite de dialogue:
		EndDialog(hwnd,0);
		break;
	default:
		break;
	}
	return 0;
}
int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR szcmd, int ishow)
{
	// Allouer de la mémoire pour notre DIALOG TEMPLATE:
	LPDLGTEMPLATE lpdt=(LPDLGTEMPLATE)GlobalAlloc(GPTR,512);
	// Définir les dimensions de notre boite dedialogue:
	lpdt->cx=200; lpdt->cy=100;
	// Définir les styles de notre boite de dialogue:
	lpdt->style=DS_CENTER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
	// Lancer notre boite de dialogue:
	DialogBoxIndirectParam(GetModuleHandle(0),lpdt,0,(DLGPROC)DlgProc,0);
	// Libérer la mémoire allouée pour notre DIALOG TEMPLATE:
	GlobalFree(lpdt);
	return 0;
}
//***********************************************************************


//*********************** Code de la DLL ********************************
#include <windows.h>

// Notre procédure de sous-classement:
LRESULT CALLBACK MyWndProc(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam)
{
	WNDPROC OldWndProc;
	// Récupérer l'adresse de la procédure originale depuis la propriété "PROP_WNDPROC" assignée à la fenêtre:
	OldWndProc=(WNDPROC)GetProp(hwnd,"PROP_WNDPROC");
	switch(message)
	{
	case WM_SYSCOMMAND:
		if(wParam==SC_CLOSE)
		{
			// Afficher le message prouvant le sous-classement de la fenêtre:
			MessageBox(hwnd,"Ce message prouve que la fenêtre a bien été sous-classée.","Sous-Classement par injection de code.",0);
		}
		break;
	case WM_NCDESTROY:
		// Retirer la propriété "PROP_WNDPROC" préalablement assignée à la fenêtre sous-classée:
		RemoveProp(hwnd,"PROP_WNDPROC");
		break;
	default:
		break;
	}
	// Appeler la procédure originale:
	return CallWindowProc(OldWndProc,hwnd,message,wParam, lParam);
}

// La fonction d'entrée DllMain:
int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		HWND hwnd;
		// Ouvrir le presse-papier:
		OpenClipboard(0);
		// récupérer le HWND de la fenêtre cible transmis par le programme injetceur:
		hwnd=(HWND)GetClipboardData(CF_PRIVATEFIRST);
		// Fermer le presse-papier:
		CloseClipboard();
		// S'assurer que le HWND est valide et que la propriété "PROP_WNDPROC" ne lui est pas assignée:
		if(IsWindow(hwnd) && !GetProp(hwnd,"PROP_WNDPROC"))
		{
			WNDPROC OldWndProc;
			// Récupérer l'adresse de la procédure originale de la fenêtre cible:
			OldWndProc=(WNDPROC)GetWindowLong(hwnd,GWL_WNDPROC);
			//Sauvegarder cette adresse dans la propriété "PROP_WNDPROC" à assigner à la fenêtre: 
			SetProp(hwnd,"PROP_WNDPROC",(HANDLE)OldWndProc);
			// Remplacer la procédure originale par la notre:
			SetWindowLong(hwnd, GWLP_WNDPROC, (LONG)MyWndProc);
		}
	}
	return 1; 
}
//**********************************************************************

 Conclusion

Téléchargez le zip pour voir les deux projets.

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !
  •   WndProcInject
    •   Injecteur
      •   Release
        • Injecteur.ex_Télécharger ce fichier [Réservé aux membres club]53 248 octets
      • Injecteur.cppTélécharger ce fichier [Réservé aux membres club]Voir ce fichier7 466 octets
      • Injecteur.slnTélécharger ce fichier [Réservé aux membres club]Voir ce fichier882 octets
      • Injecteur.vcprojTélécharger ce fichier [Réservé aux membres club]4 059 octets
      • res.rcTélécharger ce fichier [Réservé aux membres club]Voir ce fichier31 octets
      • WndProcDll.dllTélécharger ce fichier [Réservé aux membres club]3 584 octets
    •   WndProcDll

Télécharger le zip


 Sources du même auteur

Source avec Zip Source avec une capture FENÊTRE FLOTTANTE SANS FOCUS (WIN32 API)
Source avec Zip Source avec une capture SERVICE WINDOWS DANS UNE DLL LANCÉ PAR SVCHOST.EXE
Source avec Zip Source avec une capture IMPRESSION EN WIN32 API AVEC OPTIONS
Source avec Zip Source avec une capture INFOTIP SHELL EXTENSION (BULLE DE L'EXPLORATEUR WINDOWS) (WI...
Source avec Zip Source avec une capture APPLICATION MULTILINGUE UTILISANT UNICODE (WIN32)

 Sources de la même categorie

Source avec Zip WIN32 TLS LENT par dguilmain
Source avec Zip VIDER ELEMENTS DE CORBEILLE WINDOWS7 (WIN64) par BruNews
Source avec Zip Source avec une capture FIND TEXT (WIN64) par BruNews
Source avec Zip DELETE DIRECTORY (WIN64) par BruNews
Source avec Zip ENUM DIRECTORY (WIN64) par BruNews

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture SERVICE WINDOWS DANS UNE DLL LANCÉ PAR SVCHOST.EXE par racpp
Source avec Zip Source avec une capture [C/WIN32] INJECTION DE DLL 2 MÉTHODES (REMOTETHREAD PROPRE &... par deck_bsd
Source avec Zip INJECTION DE DLL DANS UN PROCESSUS par lilxam7
Source avec Zip Source avec une capture DLL POPUPIMAGE, UNE DLL POUR AFFICHER DES IMAGES À LA MANIÈR... par ndubien
Source avec Zip Source avec une capture INJECTION DE DLL DANS N'IMPORTE QUEL PROCESS par krust

Commentaires et avis

Commentaire de thenaoh le 15/06/2010 17:08:45

Merci beaucoup pour ce code !

Sauf que j'ai un petit souci, car chez moi, ça ne marche pas ... J'ai créé 2 projets sous Dev C++ (un pour l'exécutable, un pour la DLL), et j'ai copié pour chacun des 2 projets le code que tu as mis en ligne. Mon premier souci a été que "PTHREAD_START_ROUTINE" me générait une erreur de compilation. Après investigation, il semblerait que ce soit un autre nom pour "LPTHREAD_START_ROUTINE", et j'ai donc fait le changement dans mon code. Maintenant, ça compile bien, mais lorsque je lance ton code et que clique sur "Injecter", rien ne semble injecté (je n'ai pas la popup "Ce message prouve que ..." quand je ferme la fenêtre cible), alors que l'exécutable que tu as fourni dans le zip marche.

Je cherche d'où ça peut venir, mais pour l'heure, je ne trouve pas. J'ai également essayé avec Visual Studio 2008 (et donc sans changer "PTHREAD_START_ROUTINE" cette fois), mais pareil, rien ne se passe.

Saurais-tu m'éclairer ?

Commentaire de thenaoh le 15/06/2010 17:49:15

Précisions concernant le problème rencontré : Ton code fonctionne lors de la 1ère utilisation ! Si je ferme et que je relance ton appli pour reproduire le test, là, plus rien ne se passe. N'y aurait-il pas un problème de ressource quelconque non libérée ? Car après avoir lancé puis quitté ton appli, je ne peux pas supprimer la DLL "wndprocdll.dll" (par contre je peux la renommer, ainsi que renommer le répertoire parent ... Comprenne qui pourra ...).

Merci !

Commentaire de racpp le 15/06/2010 21:54:09 administrateur CS

Tu dois voir du coté de la dll. Comme précisé dans la présentation, le code de la dll est en pur C. Il ne suffit donc pas de le coller dans un nouveau projet C++. La seule modification à apporter est d'ajouter extern "C" devant la fonction DllMain:
extern "C" int APIENTRY DllMain(...
Le programme Injecteur n'utilise la dll que pour l'injecter dans le processus cible. Elle se trouve donc chargée par ce dernier et tant que ce processus n'est pas fermé la dll ne sera pas libérée donc impossible de la supprimer ou la modifier. C'est tout à fait normal. Tu n'as qu'à fermer toutes les fenêtres que tu as sous-classées pour libérer la dll. L'injecteur n'est pas responsable de sa libération. J'avais pensé ajouter un autre bouton qui appelle une autre fonction qui forcera le processus, ou tous les processus, cible à libérer la dll mais cela comporte le risque de les faire planter. Faute de temps, je ne l'ai finalement pas jugé nécessaire. Je vais revoir cette option plus tard.
Même après fermeture de l'injecteur, les fenêtres déjà choisies restent sous-classées et ont donc encore besoin de la dll. Quand tu relances l'injecteur puis tentes de re-sous-classer l'une de ces fenêtres, un message d'erreur te dira que cette fenêtre a déjà été sous-classée. C'est encore tout à fait normal. D'après les tests que j'ai faits je n'ai remarqué aucune anomalie.
J'espère que les choses sont plus claires maintenant.

Commentaire de thenaoh le 16/06/2010 10:31:09

Merci pour ces précisions !

Alors j'ai refait de nouveaux tests, et il apparaît la chose suivante : si on teste ton code sur un Notepad, ça fonctionne sans problème, on peut refaire 15 fois la même manip, ça marchera les 15 fois (et la DLL est bien libérée comme il faut). Si je teste par contre avec le visualisateur d'images Windows, ça ne marchera qu'une fois, mais pas les suivantes (et la DLL n'est pas libérée), même quand je ferme le visualisateur d'images entre chaque test (et que je fais "Actualiser" dans ton appli entre chaque fois, bien sûr).

Mais pour en revenir à mon souci de fenêtre sans focus qui ne veut pas bouger avec ma souris, j'ai fait la chose suivante : dans le code de la DLL, sous le if(wParam==SC_CLOSE), j'ai ajouté le code suivant, pour forcer le déplacement de ma fenêtre :

  else if(wParam == SC_MOVE)
  {
    RECT *pRect = (RECT *)lParam;
    SetWindowPos(hwnd, 0, pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top, 0);
  }

mais rien ne se passe. Aurais-tu une idée à ce sujet ?
Merci !!

Commentaire de racpp le 16/06/2010 13:07:57 administrateur CS

Je n'avais pas faits de tests avec le visualisateur d'images de Windows car j'utilise un autre programme. Je viens de faire un test et c'est vrai ça ne marche que la première fois avec la visionneuse de Windows et la dll n'est effectivement pas libérée. Ca ne vient pas de mon code car normalement le système devrait forcer la libération de la dll une fois le processus de la visionneuse terminé. En essayant de supprimer la dll, le message d'erreur dit : "Cette action ne peut pas être réalisée car le fichier est ouvert dans COM surrogate". Je vais ce soir creuser un peu pour y voir un peu plus clair.
Pour ta fenêtre sans focus, dans le code de la dll, colle les lignes suivantes dans la procédure de sous-classement:
case WM_MOVING:
case WM_SIZING:
{
    RECT *pRect=(RECT*)lParam;
    SetWindowPos(hwnd, 0, pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top, 0);
    return TRUE;
}

Commentaire de thenaoh le 16/06/2010 13:34:50 10/10

YEEESSSSSSSSSSSSSSSSSSSSSSSSS !!!!!!!!!!
ça y'est ça marche ! Merci infiniment !!!! J'avais mal compris où il fallait que je place ce code, mais maintenant, j'arrive sans problème à déplacer une fenêtre d'une autre application même si elle est sans focus :-)

Concernant le problème du visualisateur d'images, peut-être que ça peut intéresser d'autres personnes, mais ne te casse pas la tête pour moi, je n'en aurai pas l'utilité, et tu en as déjà fait beaucoup ! Cependant, si ça peut t'aider, lorsque j'avais fait le test avec le visualisateur d'images, j'ai pu finalement libérer la DLL en killant le processus explorer.exe . Je sais pas s'il y a un lien, m'enfin bon...

Encore une fois, merci beaucoup pour ton aide ! Me reste plus qu'à savoir comment faire pour connaître la forme du curseur de souris, notamment quand il prend la forme I-beam, mais ça fera l'objet d'un autre post ! (parce que oui, y'a aucun lien avec le sujet courant, évidemment ;-) !!)

Commentaire de racpp le 19/06/2010 20:54:25 administrateur CS

Je viens de faire une petite investigation et, effectivement, la fenêtre du visualistaur appartient bien au process explorer.exe. C'est lui qui la crée. Elle n'a donc pas son propre process. Ceci explique pourquoi la dll ne s'injecte que la première fois. Les tentatives suivantes
échouent car la dll est déjà chargée dans le process explorer.exe. Puisque le sous-classement se fait dès le chargement dans DllMain(), cette dernière ne sera plus appelée et donc la fenêtre cible ne sera pas sous-classée. Il vaut donc mieux éviter ce genre de fenêtre et ne faire des tests qu'avec celles ayant leurs propres processus. Une fois fermées, leurs processus seront terminés et notre dll se trouvera libérée.

Commentaire de Pistol_Pete le 22/06/2010 09:07:57

Salut

C'est une très bonne source et très bien commenté comme toujours!
Bravo.
J'ai néanmoins une question plus haut niveau. A quoi peut servir cette technique mise à part l'espionnage et le hackage...
Windows ne devrait t'il pas justement luter contre les injections de code, de dll, au lieu de fournir des API fonctionnelles pour le faire.    
Je prend juste l'exemple de la fonction CreateRemoteThread; a t'on vraiment besoin de créer un thread dans un process qui nous appartient pas...
Merci.

Commentaire de racpp le 23/06/2010 21:37:17 administrateur CS

Microsoft a prévu toutes ces fonctions juste pour les besoins de débogage. C'est précisé par MSDN. La technique du CreateRemoteThread() est une idée de Jeffrey Richter qui l'a bien détaillée dans son livre "Programming Applications for Microsoft Windows" publié à la fin des années 90 par Microsoft. Il y a également parlé du sous-classement de fenêtre d'un autre processus mais sans fournir d'exemple de code.
Il est toujours très utile de comprendre comment les choses fonctionnent. Ainsi, si on a besoin de contrer ces techniques dans nos applications, on sait au moins ce qu'on doit faire.

Commentaire de Pistol_Pete le 24/06/2010 08:58:37

Merci pour ta réponse.
J'ai regardé le code et franchement, je ne vois absolument pas comment contrer cette technique.
Comment tu t'y prendrais?
Mettons qu'au moment de l'attache de la dll, on face une seg fault pour planter le programme cible.
A+

Commentaire de racpp le 25/06/2010 01:38:48 administrateur CS

Franchement, je ne me suis jamais penché sur le sujet mais je pense que si on a vraiment besoin de contrer ces techniques, on a la possibilité de faire un hook API en kernel mode. On pourra intercepter et détourner pour notre processus LdrLoadDll() ou même CreateRemoteThread(). Ce n'est qu'une piste et il y en aura sûrement d'autres.

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Mettre une fenêtre graphique dans une dll [ par Arnaud ] Comment mettre une fenêtre graphique dans une dll (plus précisément dans la dll pour visual basic)MerciDjsteyhttp://www.codejeuxvideo.com SendMessage vers une fenêtre minimisée [ par Keenes ] Bonjour,Le sujet du message n'étant pas très explicite, voici de quoi il s'agit :Je cherche à réaliser une logiciel de capture d'écran, comme il en ex tutos injection de DLL ? [ par XenonGP ] Bonjour tout le monde, j'aimerais avoir quelques liens vers des tutos sur l'injection de DLL(en anglais ou en fran&#231;ais). Ce qui m'int&#233;resse, Injection dll et systray ? [ par mayti ] Hello, Voil&#224; j'injecte une dll dans un exe et je voudrais afficher une bulle dans le systray (balloon tip) mais en utilisant l'icon de cet exe. Dialog dans DLL ? [ par Zootella ] Hello all J'esseye d'utiliser dans mon programme une fen&#234;tre dialog qui se trouve dans une dll, mais la fonction qui traite les message de la fe detection d'un messageBox et fermeture automatique [ par elroulianito ] J'aimerai utiliser une fonction issue d'une dll. Le probl&#232;me est qu'&#224; l'execution de celle-ci une fen&#234;tre de type messagebox apparait m Injection de Richter ? [ par albert0 ] Bonjour, Voila, j'ai lut le chapitre 22 du bouc. de Richter, qui parle des Injections (methode avec CreateRemoteThread) Comme d'hab, j'aime bien tes Injection et DirectX [ par wxccxw ] Salut, voila j'ai une scene directX genre jeu, qui utilise des models.... et j'aimerai Injecter dedans un Dll qui change l'opaciter des models.quel st [Aide]Anti DLL Injection and API Hooking [ par belette321 ] Bon voilla je tente presentement de creer un DLL qui lors qu'il est inclue a un programme, block les tentative de "DLL Injection" et de "API Hook", Un Problème injection DLL. [ par Latino888 ] Bien le bonjour, je vous écrit aujourd'hui pour un problème d'injection DLL, en effet je shouterais tester la sécurité d'un de mes serveurs sur BF2, e


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 1,513 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales