Hooking sous nt avec createremotethread (vc++7, compilable ac le 6 aussi)

Soyez le premier à donner votre avis sur cette source.

Vue 7 232 fois - Téléchargée 328 fois

Description

bin ... ya pas grand chose a dire ...
l'executable copie une partie de son code dans la mémoire du process 'cible', et l'execute

Source / Exemple :


// code compilé avec vc++7
// c compilable aussi sur le 6, mais a vous de jouer avec les options du compilo pour que ca marche
#include <windows.h>

typedef HMODULE (WINAPI* fnLoadLibrary)(LPCTSTR LibName);
typedef FARPROC (WINAPI* fnGetProcAddress)(HMODULE hLib, LPCTSTR FuncName);
typedef int (WINAPI* fnMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
typedef BOOL (WINAPI* fnFreeLibrary)(HMODULE hLib);
typedef void (WINAPI* fnExitThread)(DWORD dwxitCode);

typedef struct InJack
{
	fnLoadLibrary pLoadLibrary;
	fnGetProcAddress pGetProcAddress;
} InJack, *pInJack;

static DWORD WINAPI RemoteEntry(pInJack Data)
{
	// vc++ (6 et 7) alloue la mémoire ds le code avec cette méthode, ainsi on a pas de lien vers le segment de données (qui n'est pas copié)
	char szUser[] = {'u','s','e','r','3','2',0};
	char szMsgBox[] = {'M','e','s','s','a','g','e','B','o','x','A',0};
	char szKernel[] = {'k','e','r','n','e','l','3','2',0};
	char szFreeLib[] = {'F','r','e','e','L','i','b','r','a','r','y',0};
	char szExitThread[] = {'E','x','i','t','T','h','r','e','a','d',0};

	HMODULE hKern = Data->pLoadLibrary(szKernel);
	fnFreeLibrary pFreeLibrary = (fnFreeLibrary)Data->pGetProcAddress(hKern, szFreeLib);
	fnExitThread pExitThread = (fnExitThread)Data->pGetProcAddress(hKern, szExitThread);
	pFreeLibrary(hKern);

	HMODULE hUser = Data->pLoadLibrary(szUser);
	fnMessageBox pMessageBox = (fnMessageBox)Data->pGetProcAddress(hUser, szMsgBox);

	pMessageBox(NULL, szUser, szMsgBox, NULL);

	pFreeLibrary(hUser);
	
	pExitThread(0); 
	// apparement sinon il aime pas le return 0, il fait une violation mémoire
	// il me semble que le compilo ne l'ait pas pris en compte ...
	return 0;
}

static void EndRemoteEntry() {}

void Main()
{
	BOOL k;
	
	// on ouvre le processus
	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 1356); // pid du process ... (ds le gestionnaire des tâches)
	int cbCodeSize = ((LPBYTE) EndRemoteEntry - (LPBYTE) RemoteEntry);
	
	// on copie le code
	LPVOID CodeMem = VirtualAllocEx(hProc, NULL, cbCodeSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	k = WriteProcessMemory(hProc, CodeMem, &RemoteEntry, cbCodeSize, 0);
	
	// on remplit les données
	InJack Data;
	HMODULE hKern = LoadLibrary("kernel32");
	Data.pGetProcAddress = (fnGetProcAddress)GetProcAddress(hKern, "GetProcAddress");
	Data.pLoadLibrary = (fnLoadLibrary)GetProcAddress(hKern, "LoadLibraryA");
	FreeLibrary(hKern);

	LPVOID DataMem = VirtualAllocEx(hProc, NULL, sizeof(Data), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
	k = WriteProcessMemory(hProc, DataMem, &Data, sizeof(Data), 0);

	DWORD ThreadID;
	HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)CodeMem, DataMem, 0, &ThreadID);
	CloseHandle(hThread);
}

Conclusion :


Dites moi si vous avez d'autres méthodes / des améliorations :)

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Utilisateur anonyme
26 mai 2003 à 20:56
Toutes mes félicitations, ton code marche et c pas partout qu'on trouve des choses de ce genre.
Petite précision pour VC++ 6 : compiler en release sans quoi ce code devient un trés bon killer de processus ;-)
Sinon, pourrais tu commenter un peu + le code ?
Nous dire par exemple à quoi servent les fonctons et à quoi correspondent les paramètres ?
Détal bizarre : pourquoi faut il initialiser les variables d'une manière barbare {'?','?','?'} plutot que d'utiliser la manière habituelle "user32" ?
Je vois bien que sa plante mais pourquoi ?

merci d'avance et encore bravo :-D
BlackGoddess Messages postés 338 Date d'inscription jeudi 22 août 2002 Statut Membre Dernière intervention 14 juin 2005
27 mai 2003 à 09:45
alors ... j'essaye d'expliquer :)

un fichier est composé de plusieurs sections, dont le header, le code, les data (pour ce qui nous interresse). un .exe est en général chargé a l'offset 400000 (en hexa). donc, pour lui, il pourra par exemple appeler l'offset 410000, et ca pointera ds le segment de data sur une chaine.

dans le processus cible, je n'ai copié que la fonction RemoteEntry, en effet, il ne sera de toutes facons pas copié a l'offset 400000 (etant deja occupé par le processus cible), donc tout ses appels à d'autres sections seront erronés -> plantage.

spécialement sou vc++ (ca marche p-e avec d'autre compilo), qd on déclare char *szUser = "user32"; il ecrit user32 dans le segment de data, et szUser devient un pointeur vers le 'u' dans le segment.

par contre, lorsqu'on déclare char szUser[] = {'u','s','e','r','3','2',0}; le compilo alloue directement les lettres une par une dans la pile par leur code ascii, donc il n'y a pas d'appel vers aucun segment.

ah, oui, qd je parle d'offset 400000, chaque processus est chargé à partir de l'offset 400000 (du moins c'est ce qu'il voit). en effet, la mémoire d'un processus n'est pas accessible aux autres (sauf cas exceptionnels).

voila, donc avec l'astuce char szUser[] = {'u','s','e','r','3','2',0}; on peut eviter les appels aux data pour les chaines. reste plus que faire pareil pour les appels de fonctions. pour cela, j'ai créé une structure dans laquel j'ai mis les adresses de GetProcAddress et LoadLibrary (cette lib etant chargée en mémoire 'partagée' .Je n'ai pas encore super bien compris le concept, mais je sais que kernel32.dll est TJS chargée au mm endroit par OS (WinMe = BFF60000 par exemple il me semble). ensuite, on ecrit donc le contenu de la structure (les 2 adresses) dans la mémoire qu'on a alloué ds le processus cible, et on envoit en paramètre de la fonction injecté un ptr vers cette structure.

ensuite, avec ces 2 api, on peut charger toutes les dll qu'on veut.

donc, ceci est juste un exemple, mais on peut faire pas mal de choses dans le processus cible. (d'apres les MSDN, CreateRemoteThread a été créé pour le débogage ... qd on cherche sur le net, on voit que bcp de code de virus l'utilise. cette api n'est pas supportée par win 9x, elle existe fait elle retourne tjs FALSE avec en GetLastError 'non pris en charge par le système').
cs_pow Messages postés 7 Date d'inscription dimanche 29 décembre 2002 Statut Membre Dernière intervention 12 janvier 2007
16 juin 2003 à 10:18
Code très interessant, cependant je n'utilise pas Visual .net, et avec ma version 6.0, j'obtiens ce message en projet console :

error LNK2001: unresolved external symbol _main

si je passe en application windows :

error LNK2001: unresolved external symbol _WinMain@16

Quelqu'un aurait une solution?

Merci d'avance :]
BlackGoddess Messages postés 338 Date d'inscription jeudi 22 août 2002 Statut Membre Dernière intervention 14 juin 2005
16 juin 2003 à 10:28
tu as ignoré toutes les libs par defaut comme j'avais dit pour avoir cette erreur.

il faut donc rajouter, ds la ligne de commande du linker /entry:Main
cs_pow Messages postés 7 Date d'inscription dimanche 29 décembre 2002 Statut Membre Dernière intervention 12 janvier 2007
16 juin 2003 à 14:38
Oui, ben en fait j'ai trouvé la solution :{
Faire un projet application windows, et renommer la fonction Main, en une fonction main.
Vala, pas plus compliqué que cela :]
(encore désolé)

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.