begin process at 2012 02 12 21:59:00
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

.Net

 > HOOKING SOUS NT AVEC CREATEREMOTETHREAD (VC++7, COMPILABLE AC LE 6 AUSSI)

HOOKING SOUS NT AVEC CREATEREMOTETHREAD (VC++7, COMPILABLE AC LE 6 AUSSI)


 Information sur la source

Note :
9 / 10 - par 3 personnes
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :.Net Niveau :Débutant Date de création :09/05/2003 Date de mise à jour :09/05/2003 20:38:04 Vu / téléchargé :5 793 / 228

Auteur : BlackGoddess

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

 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

  • // 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);
  • }
// 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 :)

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !
  • RemoteThread.ncbTélécharger ce fichier [Réservé aux membres club]35 840 octets
  • RemoteThread.slnTélécharger ce fichier [Réservé aux membres club]Voir ce fichier924 octets
  • RemoteThread.suoTélécharger ce fichier [Réservé aux membres club]7 680 octets
  • RemoteThread.vcprojTélécharger ce fichier [Réservé aux membres club]3 221 octets
  • test.cppTélécharger ce fichier [Réservé aux membres club]Voir ce fichier2 820 octets

Télécharger le zip


 Sources du même auteur

Source avec Zip STATCKTRACE : GARDER LA TRACE DE LA PILE D'APPEL
Source avec Zip ENCAPSULATION D'UNE PARTIE DE L'API SOCKET PORTABLE
Source avec Zip CLASSE POUR TRAVAILLER AVEC DES GRANDS NOMBRES ENTIERS
Source avec Zip BOT IRC
Source avec Zip EXEMPLE DE SERVEUR (MULTI-CLIENTS) TCP (WIN32 / VC++) (11 SE...

 Sources de la même categorie

Source avec Zip Source avec une capture ANALYSEUR LEXICAL par Donald180v
Source avec Zip Source avec une capture MAP_MAKER_JEU par seekplus
Source avec Zip Source avec une capture Source .NET (Dotnet) EMISSION D'UN OCTET SUR LE PORT SÉRIE - CLASSE SERIALPORT par jmchatelet01
Source avec Zip Source .NET (Dotnet) RESOLV EQU DE DEGRES N par darckangel731
Source avec Zip Source avec une capture Source .NET (Dotnet) INTEROP XCHAT / .NET : CHARGEUR DE PLUGINS MANAGÉS par TeBeCo

Commentaires et avis

Commentaire de vbnul le 26/05/2003 20:56:09

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

Commentaire de BlackGoddess le 27/05/2003 09:45:44

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 -&gt; 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').

Commentaire de pow le 16/06/2003 10:18:12

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 :]

Commentaire de BlackGoddess le 16/06/2003 10:28:16

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

Commentaire de pow le 16/06/2003 14:38:36

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é)

Commentaire de BlackGoddess le 16/06/2003 23:22:14

np lol

Commentaire de lolman27 le 12/06/2004 01:26:40

salut j utilise vc ++ 6
Le processus cible plante systematiquement que faire?^^

Commentaire de vbnul le 12/06/2004 09:27:18

Compiler en release et non en debug (je l'ai dit au dessus)

Commentaire de lolman27 le 12/06/2004 11:14:06

Exact .J arrive a faire tourner le code,et jai peu pres compris ms je n arrive pas a coder ce que je veux faire...
C est a dire charger un socket ds le prog cible et l utilise depuis le process principale...
Le pb c que je  suis pas(encore ;)) une bete en c++
Un peu d aide ne serait pas de refus :P thx
msn: lolman27@hotmail.com

Commentaire de BlackGoddess le 12/06/2004 18:33:00

utilises une dll pour faire ton "application" (dont les sockets)
puis utilises ce bout de code pour charger la dll

Commentaire de vbnul le 12/06/2004 19:08:00

La technique est décrite ici :
http://www.freecodz.net/articles/CodeInjection.html

Commentaire de lolman27 le 12/06/2004 19:19:49

merci bien

Commentaire de cancooler le 15/11/2004 12:30:04


Tres interessant ce code: clair et efficace, bravo :)

Bon deux petites questions:

no1 -  Que devient la memoire allouee dans le process cible lorsque le remote thread se termine?

J'ai essayer d'utiliser la fonction

VirtualFreeEx(hProc, CodeMem, 0, MEM_RELEASE )
ou
VirtualFreeEx(hProc, CodeMem, cbCodeSize, MEM_DECOMMIT )

Dans les deux cas il en resulte un plantage du process cible bien que la fonction VirtualFreeEx semble executee avec succes!?!


no2- J'ai ajoute la fonction suivante au debut de ton main: comme son nom l'indique elle permet d'activer les privileges 'debug'

bool EnableDebugPrivileges( void )
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;

if ( ! OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
{
//SeDebugPrivilege is not available
return 0;
}

if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )
{
//SeDebugPrivilege is not available
return 0;
}

tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
{
//SeDebugPrivilege is not available
CloseHandle( hToken );
return 0;
}



CloseHandle( hToken );

return 1;
}


Interet? Avec l'utilisation de cette fonction il est possible de creer un remote thread dans un process system. Donc a priori executer des instructions privilegiees...C cool mais bon be careful le systeme plante facilement suivant le process cible :))
Cependant, lorsque je veux afficher une MsgBox par ex en passant par un process systeme, le code est execute sans plantage, le signal sonore de la MsgBox est la, mais pas de MsgBox a l'ecran!?! Explications pliz??

Commentaire de BlackGoddess le 15/11/2004 18:57:30

mmh c'est en effet un problème ... je ne vois aucun moyen d'y parvenir ...

si tu libères ta propre mémoire, au retour du VirtualFreeEx, le pointeur d'execution pointera vers une adresse de la mémoire libérée, donc désormais inaccessible.

charger une dll puis appeler une fonction exportée qui libérerait la mémoire et ferait un ExitThread pour etre dur que le pointeur ne revienne jamais ?
mais la dll resterait chargée pour le processus hôte, on tourne en rond ...

Commentaire de pow le 16/11/2004 11:14:48

"lorsque je veux afficher une MsgBox par ex en passant par un process systeme, le code est execute sans plantage, le signal sonore de la MsgBox est la, mais pas de MsgBox a l'ecran!?! Explications pliz??"

Imo, ca c'est parsque le process cible n'a pas d'handle parent (genre pas de gestion des events/fenetres).

int MessageBox(
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

le premier parametre doit être un handle vers une fenetre parent, j'ai eu des cas où en mettant null, cela ne fonctionnait pas... (probleme que tu décris)

Commentaire de BlackGoddess le 18/11/2004 19:16:16

le problème est qu'un process systeme de dépend pas d'un utilisateur, aussi il ne sait pas dans quel contexte afficher la fenetre (sur quelle session utilisateur)

Commentaire de cancooler le 22/11/2004 12:40:35

Bon maintenant que j'en sais un peu plus, quelques petites modifs  sont a apporter a ton code pour le rendre 'clean'- j'espere que tu m'en voudras pas ;) -

D'abord, le flag "MEM_COMMIT" est suffisant pour l'appel a  VirtualAllocEx: la memoire sera reservee uniquement dans l'espace memoire virtuel du process cible.

Ensuite pour ne pas laisser de trace, il faut faire appel a VirtualFreeEx de cette facon:

VirtualFreeEx(hProc, CodeMem, 0, MEM_RELEASE);
VirtualFreeEx(hProc, DataMem, 0, MEM_RELEASE);

Mais attention, il faut etre sur que le remote thread ait bien termine son execution: pour cela on place un

WaitForSingleObject(hThread, INFINITE);

avant l'appel a VirtualFreeEx.

Enfin un CloseHandle(hProc); pour finir.


L'injection dans un process systeme fonctionne egalement - pas pour tous a priori et certains aiment pas du tout!.
Pour l'affichage de la MsgBox par ex, je recupere le hWnd de la TaskBar ( avec un FindWindow(TEXT("Shell_TrayWnd"),NULL); ) et je rajoute un champ HWND phWnd dans la struct InJack, par ex...

Pour finir je conseille a quiconque voulant *tout* savoir sur l'injection de code l'excellent article de  Robert Kuster : "Three Ways to Inject Your Code into Another Process" a l'@: http://www.codeproject.com/threads/winspy.asp


Commentaire de taye78 le 12/05/2006 02:31:10

salut, bon qqs années après... hehe
"
int cbCodeSize = ((LPBYTE) EndRemoteEntry - (LPBYTE) RemoteEntry);
"
Içi tu supposes l'ordre des fonctions en mémoire(l'une apres lautre). Cependant, le linker peut changer l'ordre des fonctions, il peut par exemple mettre RemoteEntry avant EndRemoteEntry. Ce qui planterait le process cible!
Malgrés l'option /ORDER cela reste considere "risque".

Bon code, 9/10, a+

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
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 : 3,900 sec (4)

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