You Failed !
août 27th, 2007 at 12:26 admin
Je n’ai malheureusement pas réussi à faire fonctionner le code de mon précédent post ouinz … Pourtant j’ai tenté moultes techniques voodoo et mass debugging, en fait je n’arrive tout simplement pas à comprendre d’ou provient le bug. Peut-être qu’il provient de l’utilisation des fonctions KeStackAttachProcess/KeUnstackDetachProcess qui permettent (comme leurs noms l’indique) d’attacher notre thread puis de le détacher du contexte d’un process. Si on est curieux et qu’on regarde doc du DDK :
« Note that attaching a thread to a different process can prevent asynchronous I/O operations from completing and can potentially cause deadlocks. In general, the lines of code between the call to KeStackAttachProcess and the call to KeUnstackDetachProcess should be very simple and should not call complex routines or send IRPs to other drivers. »
Ils sont marrant les gars qui ont écrit ca, sachant que je n’envoie pas d’IRP sur les autres driver ma faute devrait donc dans « and should not call complex routines »… Wow le descriptif « complex routines » aide beaucoup. Bref l’injection marche, par contre au moment de quitter c’est boom-big-badaboom-big. Comme le code est crade je préfère ne pas vous montrer sinon vous allez croire que je code avec ma souris (ce qui est parfois vraiment style !)
Autrement, on m’a parlé sur IRC d’un API exporté par le kernel appelée KeUserModeCallback qui permettrait d’effectuer un appel d’un code userland depuis le kernel. Son prototype est :
NTSTATUS KeUserModeCallback ( IN ULONG ApiNumber, IN PVOID InputBuffer, IN ULONG InputLength, OUT PVOID *OutputBuffer, IN PULONG OutputLength ) /*++ Routine Description: This function call out from kernel mode to a user mode function. Arguments: ApiNumber - Supplies the API number. InputBuffer - Supplies a pointer to a structure that is copied to the user stack. InputLength - Supplies the length of the input structure. Outputbuffer - Supplies a pointer to a variable that receives the address of the output buffer. Outputlength - Supplies a pointer to a variable that receives the length of the output buffer. Return Value: If the callout cannot be executed, then an error status is returned. Otherwise, the status returned by the callback function is returned. --*/
Après avoir lu sa définition une chose ma frappée, à quoi correspond le paramètre ApiNumber ? Hop 2-3 d’IDA, je m’apercois que KeUserModeCallback va aller lire dans le TrapFrame du thread qui l’appel, l’esp de la stack userland (avec l’API KiGetUserModeStackAddress). En effet, lors d’un syscall, le system sauvegarde le contexte (c’est à dire les registres) avant le syscall, sur la kernel stack du thread, ainsi on peut retrouver dans la structure KTRAP_FRAME le somment de la stack userland. Ensuite KeUserModeCallback va copié les arguments spécifié par InputBuffer dans la stack userland puis appel KiCallUserMode qui va effectuer après avoir modifié le TrapFrame un KiServiceExit (exit de syscall) pour tomber sur la fonction userland KiUserCallbackDispatcher. Hop, un peu de disass :
kd> uf ntdll!KiUserCallbackDispatcher ntdll!KiUserCallbackDispatcher: 7c91ead0 83c404 add esp,4 7c91ead3 5a pop edx 7c91ead4 64a118000000 mov eax,dword ptr fs:[00000018h] ; eax=TEB 7c91eada 8b4030 mov eax,dword ptr [eax+30h] ; EAX=PEB 7c91eadd 8b402c mov eax,dword ptr [eax+2Ch] ; EAX=KernelCallbackTable 7c91eae0 ff1490 call dword ptr [eax+edx*4] ; call dword ptr KernelCallbackTable[edx*4] 7c91eae3 33c9 xor ecx,ecx 7c91eae5 33d2 xor edx,edx 7c91eae7 cd2b int 2Bh ; !idt -a -> 2b: 80540d20 nt!KiCallbackReturn 7c91eae9 cc int 3
KiUserCallbackDispatcher va rechercher dans le PEB du process, le champ KernelCallbackTable, comme son nom l’indique il s’agit d’un table de pointeurs de fonctions. C’est là qu’intervient le paramètre ApiNumber passé à KeUserModeCallback car celui-ci nous permet de choisir l’indice de la fontion à appeler. Voici la liste :
kd> dds poi(7ffde000+2c) l 62 7e392970 7e3ae373 USER32!__fnCOPYDATA 7e392974 7e3d8583 USER32!__fnCOPYGLOBALDATA 7e392978 7e39b4e8 USER32!__fnDWORD 7e39297c 7e39da97 USER32!__fnNCDESTROY 7e392980 7e3d853c USER32!__fnDWORDOPTINLPMSG 7e392984 7e3d873d USER32!__fnINOUTDRAG 7e392988 7e3bb815 USER32!__fnGETTEXTLENGTHS 7e39298c 7e3d8a12 USER32!__fnINCNTOUTSTRING 7e392990 7e3ad278 USER32!__fnINCNTOUTSTRINGNULL 7e392994 7e3d88df USER32!__fnINLPCOMPAREITEMSTRUCT 7e392998 7e39f9a8 USER32!__fnINLPCREATESTRUCT 7e39299c 7e3d891d USER32!__fnINLPDELETEITEMSTRUCT 7e3929a0 7e3cfc8c USER32!__fnINLPDRAWITEMSTRUCT 7e3929a4 7e3d895b USER32!__fnINLPHLPSTRUCT 7e3929a8 7e3d895b USER32!__fnINLPHLPSTRUCT 7e3929ac 7e3d877d USER32!__fnINLPMDICREATESTRUCT 7e3929b0 7e3cf3fc USER32!__fnINOUTLPMEASUREITEMSTRUCT 7e3929b4 7e39d080 USER32!__fnINLPWINDOWPOS 7e3929b8 7e39fbe5 USER32!__fnINOUTLPPOINT5 7e3929bc 7e39cf77 USER32!__fnINOUTLPSCROLLINFO 7e3929c0 7e3be24d USER32!__fnINOUTLPRECT 7e3929c4 7e39d1b6 USER32!__fnINOUTNCCALCSIZE 7e3929c8 7e39cf77 USER32!__fnINOUTLPSCROLLINFO 7e3929cc 7e3d87cf USER32!__fnINPAINTCLIPBRD 7e3929d0 7e3d8836 USER32!__fnINSIZECLIPBRD 7e3929d4 7e3b0d01 USER32!__fnINDESTROYCLIPBRD 7e3929d8 7e39f599 USER32!__fnINSTRING 7e3929dc 7e39f599 USER32!__fnINSTRING 7e3929e0 7e3acd83 USER32!__fnINDEVICECHANGE 7e3929e4 7e3d8aa7 USER32!__fnINOUTNEXTMENU 7e3929e8 7e3d91c5 USER32!__fnLOGONNOTIFY 7e3929ec 7e3d84f8 USER32!__fnOUTDWORDDWORD 7e3929f0 7e3d84f8 USER32!__fnOUTDWORDDWORD 7e3929f4 7e3d84b5 USER32!__fnOUTDWORDINDWORD 7e3929f8 7e3d889c USER32!__fnOUTLPRECT 7e3929fc 7e3ad278 USER32!__fnINCNTOUTSTRINGNULL 7e392a00 7e3d895b USER32!__fnINLPHLPSTRUCT 7e392a04 7e3ad278 USER32!__fnINCNTOUTSTRINGNULL 7e392a08 7e3d85fb USER32!__fnSENTDDEMSG 7e392a0c 7e39d665 USER32!__fnINOUTSTYLECHANGE 7e392a10 7e3b01d4 USER32!__fnHkINDWORD 7e392a14 7e3cf6ca USER32!__fnHkINLPCBTACTIVATESTRUCT 7e392a18 7e3cf60c USER32!__fnHkINLPCBTCREATESTRUCT 7e392a1c 7e3d8b9e USER32!__fnHkINLPDEBUGHOOKSTRUCT 7e392a20 7e3b1663 USER32!__fnHkINLPMOUSEHOOKSTRUCTEX 7e392a24 7e3d8b24 USER32!__fnHkINLPKBDLLHOOKSTRUCT 7e392a28 7e3d8b61 USER32!__fnHkINLPMSLLHOOKSTRUCT 7e392a2c 7e39f926 USER32!__fnHkINLPMSG 7e392a30 7e3d8ae7 USER32!__fnHkINLPRECT 7e392a34 7e3cee05 USER32!__fnHkOPTINLPEVENTMSG 7e392a38 7e3d8c89 USER32!__ClientCopyDDEIn1 7e392a3c 7e3d8ccb USER32!__ClientCopyDDEIn2 7e392a40 7e3d8d2e USER32!__ClientCopyDDEOut1 7e392a44 7e3d8cfd USER32!__ClientCopyDDEOut2 7e392a48 7e3a0ae1 USER32!__ClientCopyImage 7e392a4c 7e3d8d62 USER32!__ClientEventCallback 7e392a50 7e3b19b6 USER32!__ClientFindMnemChar 7e392a54 7e3aa7c1 USER32!__ClientFontSweep 7e392a58 7e3d8c1c USER32!__ClientFreeDDEHandle 7e392a5c 7e3adea5 USER32!__ClientFreeLibrary 7e392a60 7e3a7b3c USER32!__ClientGetCharsetInfo 7e392a64 7e3d8c53 USER32!__ClientGetDDEFlags 7e392a68 7e3d8dac USER32!__ClientGetDDEHookData 7e392a6c 7e3cf795 USER32!__ClientGetListboxString 7e392a70 7e3a7c1d USER32!__ClientGetMessageMPH 7e392a74 7e3abb9c USER32!__ClientLoadImage 7e392a78 7e3adbc9 USER32!__ClientLoadLibrary 7e392a7c 7e3a106d USER32!__ClientLoadMenu 7e392a80 7e3a8022 USER32!__ClientLoadLocalT1Fonts 7e392a84 7e3a9ffc USER32!__ClientLoadRemoteT1Fonts 7e392a88 7e3d8e4b USER32!__ClientPSMTextOut 7e392a8c 7e3d8ea1 USER32!__ClientLpkDrawTextEx 7e392a90 7e3d8f05 USER32!__ClientExtTextOutW 7e392a94 7e3d8f6a USER32!__ClientGetTextExtentPointW 7e392a98 7e3d8de9 USER32!__ClientCharToWchar 7e392a9c 7e3a7f29 USER32!__ClientAddFontResourceW 7e392aa0 7e39a13e USER32!__ClientThreadSetup 7e392aa4 7e3d9023 USER32!__ClientDeliverUserApc 7e392aa8 7e3d8fc1 USER32!__ClientNoMemoryPopup 7e392aac 7e39cf28 USER32!__ClientMonitorEnumProc 7e392ab0 7e3d921a USER32!__ClientCallWinEventProc 7e392ab4 7e3d8be5 USER32!__ClientWaitMessageExMPH 7e392ab8 7e39fb10 USER32!__ClientWOWGetProcModule 7e392abc 7e3d925d USER32!__ClientWOWTask16SchedNotify 7e392ac0 7e3d9036 USER32!__ClientImmLoadLayout 7e392ac4 7e3d9092 USER32!__ClientImmProcessKey 7e392ac8 7e3d90d2 USER32!__fnIMECONTROL 7e392acc 7e3d8666 USER32!__fnINWPARAMDBCSCHAR 7e392ad0 7e3bb815 USER32!__fnGETTEXTLENGTHS 7e392ad4 7e3d89ac USER32!__fnINLPKDRAWSWITCHWND 7e392ad8 7e3abda8 USER32!__ClientLoadStringW 7e392adc 7e3e55f7 USER32!__ClientLoadOLE 7e392ae0 7e3e54d4 USER32!__ClientRegisterDragDrop 7e392ae4 7e3e5513 USER32!__ClientRevokeDragDrop 7e392ae8 7e3d9182 USER32!__fnINOUTMENUGETOBJECT 7e392aec 7e3b03b7 USER32!__ClientPrinterThunk 7e392af0 7e3d929c USER32!__fnOUTLPCOMBOBOXINFO 7e392af4 7e3d92dc USER32!__fnOUTLPSCROLLBARINFO
La fonction disponible que j’ai tout de suite remarqué est ClientLoadLibrary (indice 66), equivalant à LoadLibrary ! Il est donc possible de loader une dll dans un process depuis le kernel, juste en appelant KeUserModeCallback avec dans le InputBuffer le path de la dll à charger. Le soucis, c’est qu’un des threads du process visé doit appeler cette fonction par lui-même depuis le kernel land à cause de la TrapFrame. Je me suis donc dit, « bah balance un kernel APC à un des threads du process, fait lui lancer KeUserModeCallback et ca sera bion !! » ….
Grande fut ma déception lorsque qu’après mass-tentative, je remarqua que la fonction chargé de délivrer les APC, KiDeliverApc, prennait en paramètre un pointeur sur une TrapFrame :
VOID KiDeliverApc ( IN KPROCESSOR_MODE PreviousMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame );
Forcément, la plupart du temps le paramètre TrapFrame étant NULL, demander à l’APC d’appeler KeUserModeCallback qui à besoin du TrapFrame pour copier ses arguements dans la user stack, était impossible, l’échec, encore …
Même en demander à l’APC de forcer en copiant l’adresse du TrapFrame dans la structure KTHREAD, je me prenais un magnifique BSOD.
Bref pour que KeUserModeCallback marche, il faut que le thread l’appel de lui-même. Ca pourrait se faire en hookant un syscall ou un gestionnaire d’IOCTL mais bon, ce n’est pas le but, je voulais au départ injecter une dll simplement depuis le kernel dans un process, and … I FAILED !
refs :
http://www.cmkrnl.com/arc-userapc.html
http://www.illmob.org/files/text/29a7/Articles/29A-7.003
Entry Filed under: Non classé
9 Comments
1. newsoft | août 27th, 2007 at 13:07
You failed *miserably*
Les deadlocks ça se débogue.
http://www.dumpanalysis.org/blog/index.php/2007/02/09/crash-dump-analysis-patterns-part-9a/
Dépêche toi sinon je prends une stagiaire russe l’année prochaine
2. Necroalbert | août 27th, 2007 at 21:17
Merci pour cet article,
je lis toujours passionément les articles en n’en suivant que 1/4.
donc se sera avec deux croissants pour moi
3. TheShade | août 30th, 2007 at 16:57
Dites ca a rien a voir mais comment on fait un Sleep en ring0 dans un kmd ? J’ai cherché des fonctions noyaux mais la seule chose que j’ai trouvée c’est KeSetTimer() et ses congénères…
4. admin | août 30th, 2007 at 18:11
KeDelayExecutionThread
5. TheShade | août 30th, 2007 at 18:29
ok merci beaucoup !
Sinon ca correspond à quoi le « alertable » ?
6. admin | août 30th, 2007 at 18:40
Alertable permet d’exécuter un APC quand le thread est en attente. Te prend pas la tête avec et met le à FALSE.
7. Injection de code dans un&hellip | janvier 24th, 2010 at 08:15
[...] afin d'invoquer ClientLoadLibrary, tout allait pour le mieu dans le meilleur des mondes mais … lire les détails Remplis sous: Win32 Laisser un commentaire Commentaires (0) Trackbacks (0) (Souscrire aux [...]
8. Analyzinglocalprivilegees&hellip | septembre 20th, 2012 at 07:00
[...] http://www.ivanlef0u.tuxfamily.org/?p=68 [...]
9. Callgate to user : nt!KeU&hellip | décembre 23rd, 2013 at 12:34
[...] You Failed ! by @Ivanlef0u [...]
Trackback this post