Hooking adapter functions on XP sp2

Home Forums Discussions General Hooking adapter functions on XP sp2

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #5043
    s0larian
    Participant

      Hi there,

      I have just tried hooking NDIS packet sends at a lower level than NDIS_OPEN_BLOCK, by patching miniport characteristics submitted to NdisMRegisterMiniport(). Theoretically, this would allow me to process packets after NDIS has finished with them, and just before they are fed to adapters. I mean I am intercepting the exact point when they are being fed to adapters.

      So, I can overwrite SendHandler/SendPacketsHandler, my function is invoked and I can pass the submitted packet descriptor to the real handler – no problem so far.

      The issue comes up when I copy the packet and submit the newly created packet descriptor. _ndisMSendCompleteX@12 crashes trying to access something inside the packet, just after referencing _ndisPacketStackSize.

      Now, I have worked around this particular problem by hooking a send handler at slightly higher level, in NDIS_OPEN_BLOCK, and the entire outgoing packet path works well. Bbut, I am interested in why this is happening.

      So, I was wondering if somebody has seen this and can shed some light on the situation. BTW, a very similar bit of code is present in NdisReturnPackets, and it also crashes very shortly after referencing _ndisPacketStackSize on the incoming path.

      Thanks in advance.

      #6097
      s0larian
      Participant
        00025BA0 ; __stdcall ndisMSendCompleteX(x, x, x)
        00025BA0 _ndisMSendCompleteX@12 proc near ; CODE XREF: ndisMSendX(x,x)+2715p
        00025BA0 ; ndisMSendPacketsX(x,x,x)+1DFp ...
        00025BA0
        00025BA0 var_2 = byte ptr -2
        00025BA0 var_1 = byte ptr -1
        00025BA0 mah = dword ptr 8
        00025BA0 packet = dword ptr 0Ch
        00025BA0 status = dword ptr 10h
        00025BA0
        00025BA0
        00025BA0 mov edi, edi
        00025BA2 push ebp
        00025BA3 mov ebp, esp
        00025BA5 push ecx
        00025BA6 push ebx
        00025BA7 push esi
        00025BA8 push edi
        00025BA9 mov cl, 2
        00025BAB call ds:__imp_@KfRaiseIrql@4 ; KfRaiseIrql(x)
        00025BB1 mov ebx, [ebp+mah]
        00025BB4 test byte ptr [ebx+3Ch], 40h
        00025BB8 mov esi, [ebp+packet]
        00025BBB mov [ebp+var_1], al
        00025BBE jz short loc_25BD4
        00025BC0 movzx eax, word ptr [esi+1Eh]
        00025BC4 cmp dword ptr [eax+esi+34h], 0
        00025BC9 jz short loc_25BD4
        00025BCB mov edx, esi
        00025BCD mov ecx, ebx
        00025BCF call @ndisMFreeSGList@8 ; ndisMFreeSGList(x,x)
        00025BD4
        00025BD4 loc_25BD4: ; CODE XREF: ndisMSendCompleteX(x,x,x)+1Ej
        00025BD4 ; ndisMSendCompleteX(x,x,x)+29j
        00025BD4 test byte ptr [ebx+1D4h], 4
        00025BDB jnz loc_262FD
        00025BE1
        00025BE1 loc_25BE1: ; CODE XREF: ndisMSendCompleteX(x,x,x)+766j
        00025BE1 ; ndisMSendCompleteX(x,x,x)+772j
        00025BE1 mov ecx, _ndisPacketStackSize
        00025BE7 lea edx, [esi-4]
        00025BEA mov eax, [edx]
        00025BEC cmp eax, ecx
        00025BEE jnb short loc_25C43
        00025BF0 sub eax, ecx
        00025BF2 lea eax, [eax+eax*2]
        00025BF5 lea eax, [esi+eax*8-8]
        00025BF9
        00025BF9 loc_25BF9: ; CODE XREF: ndisMSendCompleteX(x,x,x)+A5j
        00025BF9 or ecx, 0FFFFFFFFh
        00025BFC lock xadd [edx], ecx
        00025C00 mov edi, [eax+8] ; <--- the crash occurs here
        #6098
        Vadim Smirnov
        Keymaster

          The issue comes up when I copy the packet and submit the newly created packet descriptor. _ndisMSendCompleteX@12 crashes trying to access something inside the packet, just after referencing _ndisPacketStackSize.

          Well, as far as I can see without going deep into the problem the only difference is that original packet was preprocessed by NDIS send handler but your packet was not. You can analyze what fields were exactly referenced and fix it. I would not recommend this because internal NDIS packet processing may change from OS and SP.

          Another way is intercepting NdisMSendComplete and checking if it is your packet descriptor passed to it and if yes then releasing your packet resource without passing it to NDIS. Also don’t forget to release packet descriptors for the original packets.

          #6099
          s0larian
          Participant

            Hi there, thank you for a quick reply. Please see my comments below.

            @SerpentFly wrote:

            Well, as far as I can see without going deep into the problem the only difference is that original packet was preprocessed by NDIS send handler but your packet was not. You can analyze what fields were exactly referenced and fix it. I would not recommend this because internal NDIS packet processing may change from OS and SP.

            Right, I tried that, but could not see any differences in the packet… I have found a usenet thread that seems to be related though:

            usenet post

            @SerpentFly wrote:

            Another way is intercepting NdisMSendComplete and checking if it is your packet descriptor passed to it and if yes then releasing your packet resource without passing it to NDIS. Also don’t forget to release packet descriptors for the original packets.

            Yes, indeed that is what I am trying to do. I think you are 100% on the money here – my SendComplete handler is not invoked, and, it looks like NDIS dies because it expects something in the returned packet, which it thinks it submitted.

            So, I tried hooking SendCompleteHandler inside NDIS_MNIPORT_BLOCK in MyMiniportInitialize just before I forward the call to the adapter, but, it does not seem to work. I mean my function is not invoked… Here is the stack at the point of the crash:

            f5d7f618 f777fcb5 8370e6c0 8380bf30 00000000 NDIS!ndisMSendCompleteX+0x71
            f5d7f634 f778163c 837472e8 00000000 8385feb8 vmxnet+0xcb5
            f5d7f674 f74dc4e7 00000001 f5d7f6d4 00000001 vmxnet+0x263c
            f5d7f6cc f74dc1bb 8380bf30 837472e8 f74dfea8 tf!`anonymous namespace’::SendToAdapter+0x172 [c:worktftraffic.cpp @ 314]
            f5d7f6ec bad5df86 837472e8 f5d7f720 00000001 tf!MiSendPackets+0x7b [c:worktftraffic.cpp @ 180]
            f5d7f714 bacbb528 8379ae08 8385fed8 8385fea0 NDIS!ndisMSendX+0x1bd
            f5d7f750 bad5b985 836aa7f8 8385fed8 00000002 psched!MpSend+0x706
            f5d7f778 f6046454 836b8958 8385fed8 8369c768 NDIS!ndisMSendX+0x1d6
            f5d7f79c f60464f8 0069c70e ffffffff 8385fed8 tcpip!IPTransmit+0x2816
            f5d7f7c8 f604470a 8369c768 f5d7f800 00000001 tcpip!ARPRcv+0x85
            f5d7f7f8 f60573de 83694be8 ffffffff 8385fed8 tcpip!IPTransmit+0xacc
            f5d7f82c f60526c1 ffffffff 8385fed8 83606020 tcpip!ARPRcv+0x10f6b

            Hmmm… this should work, ndis.h defines the NdisMSendComplete() macro and it uses that member… strange… What do you think? I could also hook a SendCompleteHandler inside NDIS_OPEN_BLOCK, but, that would not be the earliest function… What do you think?

            Thanks in advance!

            #6100
            Vadim Smirnov
            Keymaster

              Hmmm… this should work, ndis.h defines the NdisMSendComplete() macro and it uses that member… strange… What do you think? I could also hook a SendCompleteHandler inside NDIS_OPEN_BLOCK, but, that would not be the earliest function… What do you think?

              If miniport driver was compiled with BINARY_COMPATIBLE flag set (allows having same binary for Windows 9x and NT) then NdisMSendComplete called as NDIS export not as macro. May be this is the reason…

              #6101
              s0larian
              Participant

                @SerpentFly wrote:

                If miniport driver was compiled with BINARY_COMPATIBLE flag set (allows having same binary for Windows 9x and NT) then NdisMSendComplete called as NDIS export not as macro. May be this is the reason…

                Hmmm…. I don’t think this this is the case. Here is the function from vmxnet.sys which implements their network adapter. This is a v5 miniport according to the DriverEntry function…

                The call instruction at 00010CAF invokes ndisMSendCompleteX() which generates the crash. The code seems to dereference arg0+4 and then invoke a function from a structure. The offset is 0xEC.

                Shit, I don’t think this structure is documented in ndis.h…. I think I might have to go back to hooks using NDIS_OPEN_BLOCK….

                What do you think?


                .text:00010C7E sub_10C7E proc near ; CODE XREF: sub_10CD8+16p
                .text:00010C7E ; sub_10CFA+62p ...
                .text:00010C7E
                .text:00010C7E arg_0 = dword ptr 8
                .text:00010C7E arg_4 = byte ptr 0Ch
                .text:00010C7E
                .text:00010C7E push ebp
                .text:00010C7F mov ebp, esp
                .text:00010C81 push ebx
                .text:00010C82 xor ebx, ebx
                .text:00010C84 cmp [esi], ebx
                .text:00010C86 jle short loc_10CD3
                .text:00010C88 cmp [ebp+arg_4], bl
                .text:00010C8B push edi
                .text:00010C8C mov edi, [ebp+arg_0]
                .text:00010C8F jz short loc_10C9D
                .text:00010C91 mov dl, [edi+10h] ; NewIrql
                .text:00010C94 lea ecx, [edi+0Ch] ; SpinLock
                .text:00010C97 call ds:KfReleaseSpinLock
                .text:00010C9D
                .text:00010C9D loc_10C9D: ; CODE XREF: sub_10C7E+11j
                .text:00010C9D cmp [esi], ebx
                .text:00010C9F jle short loc_10CC0
                .text:00010CA1 lea edi, [esi+4]
                .text:00010CA4
                .text:00010CA4 loc_10CA4: ; CODE XREF: sub_10C7E+3Dj
                .text:00010CA4 mov eax, [ebp+arg_0]
                .text:00010CA7 mov eax, [eax+4]
                .text:00010CAA push 0
                .text:00010CAC push dword ptr [edi]
                .text:00010CAE push eax
                .text:00010CAF call dword ptr [eax+0ECh] ; This instruction calls
                .text:00010CAF ; NDIS!ndisMSendCompleteX
                .text:00010CB5 inc ebx
                .text:00010CB6 add edi, 4
                .text:00010CB9 cmp ebx, [esi]
                .text:00010CBB jl short loc_10CA4
                .text:00010CBD mov edi, [ebp+arg_0]
                .text:00010CC0
                .text:00010CC0 loc_10CC0: ; CODE XREF: sub_10C7E+21j
                .text:00010CC0 cmp [ebp+arg_4], 0
                .text:00010CC4 jz short loc_10CD2
                .text:00010CC6 lea ecx, [edi+0Ch] ; SpinLock
                .text:00010CC9 call ds:KfAcquireSpinLock
                .text:00010CCF mov [edi+10h], al
                .text:00010CD2
                .text:00010CD2 loc_10CD2: ; CODE XREF: sub_10C7E+46j
                .text:00010CD2 pop edi
                .text:00010CD3
                .text:00010CD3 loc_10CD3: ; CODE XREF: sub_10C7E+8j
                .text:00010CD3 pop ebx
                .text:00010CD4 pop ebp
                .text:00010CD5 retn 8
                .text:00010CD5 sub_10C7E endp
                #6102
                s0larian
                Participant

                  …so, my outgoing packet path hooks made using NDIS_OPEN_BLOCK work well, and it NDIS seems to behave. It looks like there are some very weird packet processing side effects that one would have to manage when hooking MINIPORT_CHARS functions…..

                  I wonder if anyone managed to get them to work properly?….

                  #6103
                  Vadim Smirnov
                  Keymaster

                    So, I tried hooking SendCompleteHandler inside NDIS_MNIPORT_BLOCK in MyMiniportInitialize just before I forward the call to the adapter, but, it does not seem to work. I mean my function is not invoked…

                    SendCompleteHandler seems to be initialized by NDIS after calling miniport InitializeHandler (and your MyMiniportInitialize), that is why your hook does not work.

                    P.S. You can apply your hook on first SendHandler invoked, an example.

                    #6104
                    s0larian
                    Participant

                      Well, the entire thing seems to be quite strange… I have tried hooking real protocol functions that are submitted to NdisRegisterProtocol() but I get similar crashes to what I have mentioned above…. So, the only easy way forward seems to be hooking the contents of NDIS_OPEN_BLOCK, which is a shame.

                      I mean I do have a working solution, but I would have really liked to be at the point when adapters are fed outgoing packets and protocols receive incoming data, but alas, something very tricky is going on with packet descriptors.

                      Does anyone know how their stacking feature works? There are fields just outside the NDIS_PACKET structure that are used…. I wonder, what should I disassemble to figure out what has to be done, in order to get these highest and lowest level hooks to work….

                      Thanks!

                    Viewing 9 posts - 1 through 9 (of 9 total)
                    • You must be logged in to reply to this topic.