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


  • 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



AltStyle によって変換されたページ (->オリジナル) /