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


Calendar

décembre 2017
L Ma Me J V S D
« fév    
 123
45678910
11121314151617
18192021222324
25262728293031

Most Recent Posts