Trip in da TCP/IP
Je suis de retour, plus mad que jamais, et cette fois-ci, vous allez souffrir ! En effet, vous allez découvrir le voyage effectué par un packet TCP au sein du windows. À partir de l’appel à la fonction connect, jusqu’a la dernière instruction assembleur faisant appel à la carte réseau. Évidemment si j’ai fait cela, c’était surtout pour mieux comprendre comment sont mises en places les différences couches réseau du Windows. Préparez-vous à une aventure dont vous ne reviendrez pas indemne !
L’API Winsock respecte les sockets BDS et est dans implémenté dans libraire ws2_32.dll. Cette dll se base sur différents SPI (Service Provider Interface), on a par exemple le NameSpace SPI (NSP), qui permet d’effectuer des requêtes DNS avec des fonctions comme gethostbyname et surtout le Winsock Provider (WSP) qui va send les demandes aux couches inférieures. Ces 2 providers sont fourni par mswsock.dll qui est vraiment le coeur de l’API Winsock servant à envoyer les requêtes au noyau à travers un ZwDeviceIoControlFile comme on peut le voir avec la call stack suivante :
ntdll.dll!KiFastSystemCall ntdll.dll!ZwDeviceIoControlFile+0xc mswsock.dll!QueryNbtWins+0x50 mswsock.dll!TryNbt+0x22 mswsock.dll!NSPLookupServiceNext+0x57e WS2_32.dll!NSPROVIDER::NSPLookupServiceNext+0x17 WS2_32.dll!NSPROVIDERSTATE::LookupServiceNext+0x1c WS2_32.dll!NSQUERY::LookupServiceNext+0xae WS2_32.dll!WSALookupServiceNextW+0x78 WS2_32.dll!WSALookupServiceNextA+0x63 WS2_32.dll!getxyDataEnt+0xa1 WS2_32.dll!gethostbyname+0xb4 rezo.exe+0x2e6 kernel32.dll!BaseProcessStart+0x23
Depuis que j’ai ouvert ce blog, je fearais l’exploration de l’implémentation réseau sous Windows, après avoir passé pas mal de temps dessus, je crois qu’au final j’avais raison de pas m’y aventurer. Je voulais en fait, suivre le parcourt d’un packet, à partir du moment ou l’on appel la fonction send(), jusqu’à l’arrivé sur la carte réseau. Pour cela j’ai employé une méthode appelée le brutal tracing, l’avantage de cette technique c’est quelle est super simple à mettre en oeuvre, à l’aide de IDA et de WinDbg on regarde les différentes fonctions des lib/drv et puis on trace pour vérifier qu’on ne s’est pas trompé.
Alors première étape, se coder un petit programme de base. Un simple client qui send un « GET / HTTP/1.1″ suffira. Le but, suivre le parcourt de nos datas après l’appel avec la fonction send(). Voici le code (très simple) du client :
#include <Winsock2.h> #include <stdio.h> //compil with vc6 //fuck d4 CRT sh1t #pragma comment (linker, "/nodefaultlib:libc.lib") #pragma comment (linker, "/entry:\"main\"") #pragma comment (lib, "msvcrt.lib") #pragma comment (lib, "ws2_32.lib") ULONG main() { WORD Ver; WSADATA Wsa; SOCKET Socket; SOCKADDR_IN Sin; char SendBuff[]= "GET / HTTP/1.1rn" "rn"; Ver=MAKEWORD(2, 2); if(WSAStartup(Ver, &Wsa)) { printf("Error with WSAStartupn"); return 0; } Socket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(Socket==INVALID_SOCKET) { printf("Error with socket : %dn", WSAGetLastError()); WSACleanup(); return 0; } RtlZeroMemory(&Sin, sizeof(SOCKADDR_IN)); // Create a sockaddr_in object and set its values. Sin.sin_family=AF_INET; Sin.sin_addr.s_addr=inet_addr("209.85.135.103"); //IP google Sin.sin_port=htons(80); if(connect(Socket, (SOCKADDR*)&Sin, sizeof(SOCKADDR_IN))==SOCKET_ERROR) { printf("Error with connect failed : %dn", WSAGetLastError()); closesocket(Socket); return 0; } if(send(Socket, SendBuff, sizeof(SendBuff), 0)!=0) { printf("Error with send : %dn", WSAGetLastError()); closesocket(Socket); return 0; } //recv(Socket, Buff, sizeof(Buff), 0); //printf("%s", Buff); closesocket(Socket); WSACleanup(); return 0; }
Ok, on est partit. Déja en tracant la fonction send on peut voir un enormous call :
71AB42CF 53 PUSH EBX 71AB42D0 8D4D FC LEA ECX,DWORD PTR SS:[EBP-4] 71AB42D3 51 PUSH ECX 71AB42D4 FF75 F8 PUSH DWORD PTR SS:[EBP-8] 71AB42D7 8D4D 08 LEA ECX,DWORD PTR SS:[EBP+8] 71AB42DA 57 PUSH EDI 71AB42DB 57 PUSH EDI 71AB42DC FF75 14 PUSH DWORD PTR SS:[EBP+14] 71AB42DF 8945 F0 MOV DWORD PTR SS:[EBP-10],EAX 71AB42E2 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] 71AB42E5 51 PUSH ECX 71AB42E6 6A 01 PUSH 1 71AB42E8 8D4D F0 LEA ECX,DWORD PTR SS:[EBP-10] 71AB42EB 51 PUSH ECX 71AB42EC FF75 08 PUSH DWORD PTR SS:[EBP+8] 71AB42EF 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX 71AB42F2 8B46 0C MOV EAX,DWORD PTR DS:[ESI+C] 71AB42F5 FF50 64 CALL NEAR DWORD PTR DS:[EAX+64]
Le problème c’est qu’on ne peut connaître la destination du call en dead-listing, alors on sort le Olly et on voit qu’on tombe dans la dll mswsock. De plus, il serait tout de même sympa de savoir sur quoi pointe eax, en dumpant la zone mémoire pointée on peut voir :
00146C18 02 00 00 00 00 00 A5 71 D9 B5 A6 71 98 69 A5 71 .....¥qÙµ¦q˜i¥q 00146C28 0F 7F A6 71 A1 4D A5 71 54 AE A6 71 4D 77 A6 71 ¦q¡M¥qT®¦qMw¦q 00146C38 5F 40 A5 71 D0 53 A5 71 B3 AE A6 71 29 67 A5 71 _@¥qÐS¥q³®¦q)g¥q 00146C48 EF 64 A5 71 21 B0 A6 71 31 B1 A6 71 49 3D A5 71 ïd¥q!°¦q1±¦qI=¥q 00146C58 E5 5F A5 71 D5 AD A6 71 DB 5C A5 71 90 A3 A6 71 å_¥qÕ¦qÛ¥q£¦q 00146C68 5D 76 A5 71 42 43 A5 71 93 9A A6 71 45 31 A5 71 ]v¥qBC¥q“š¦qE1¥q 00146C78 58 2D A5 71 47 58 A5 71 71 9C A6 71 85 2E A5 71 X-¥qGX¥qqœ¦q….¥q 00146C88 BB 51 A5 71 D1 98 A6 71 15 46 A5 71 0E 94 A5 71 »Q¥qј¦qF¥q”¥q
Youpi une jolie table de fonctions. A ce moment-là je me souvenu que j’avais fait un post appelé « Winsock Reversing » et que cette table était en fait initialisé par la fonction WSPStartup qui la remplissait des diverses fonctions du Winsock Provider. Bien évidemment si on regarde le nom des fonctions de cette table, on trouve à l’offet 0×64, l’adresse de la fonction WSPSend.
kd> dds @eax l 20 001476f8 00000001 001476fc 71a50000 mswsock!_imp__GetUserNameA(mswsock+0x0) 00147700 71a6b5d9 mswsock!WSPAccept 00147704 71a56998 mswsock!WSPAddressToString 00147708 71a67f0f mswsock!WSPAsyncSelect 0014770c 71a54da1 mswsock!WSPBind 00147710 71a6ae54 mswsock!WSPCancelBlockingCall 00147714 71a6774d mswsock!WSPCleanup 00147718 71a5405f mswsock!WSPCloseSocket 0014771c 71a553d0 mswsock!WSPConnect 00147720 71a6aeb3 mswsock!WSPDuplicateSocket 00147724 71a56729 mswsock!WSPEnumNetworkEvents 00147728 71a564ef mswsock!WSPEventSelect 0014772c 71a6b021 mswsock!WSPGetOverlappedResult 00147730 71a6b131 mswsock!WSPGetPeerName 00147734 71a53d49 mswsock!WSPGetSockName 00147738 71a55fe5 mswsock!WSPGetSockOpt 0014773c 71a6add5 mswsock!WSPGetQOSByName 00147740 71a55cdb mswsock!WSPIoctl 00147744 71a6a390 mswsock!WSPJoinLeaf 00147748 71a5765d mswsock!WSPListen 0014774c 71a54342 mswsock!WSPRecv 00147750 71a69a93 mswsock!WSPRecvDisconnect 00147754 71a53145 mswsock!WSPRecvFrom 00147758 71a52d58 mswsock!WSPSelect 0014775c 71a55847 mswsock!WSPSend <---- 00147760 71a69c71 mswsock!WSPSendDisconnect 00147764 71a52e85 mswsock!WSPSendTo 00147768 71a551bb mswsock!WSPSetSockOpt 0014776c 71a698d1 mswsock!WSPShutdown 00147770 71a54615 mswsock!WSPSocket
En fait, cette implémentation permet d’avoir des LSP (Layer Service Provider), par exemple, si vous voulez rajouter une couche SSL au dessous des Winsock et au dessus du provider TCP il suffit de crée un LSP avec la fonction WSCInstallProvider. Jonathan Levin nous expose cette méthode permettant de faire du « socket hijacking » dans une conf de la REcon 2005 « The Dark Side of Winsock » qui vous pouvez trouver ici.
En fait lors de l’initialisation,la fonction WSAStartup va parcourir dans l’ordre des dwCatalogEntryId le catalogue des providers puis sélectionner ceux qui correspondent à notre type socket et les chainer entre eux. Voici le catalogue des providers par défaut :
Winsock 32-bit Catalog: ======================= 1001 - MSAFD Irda [IrDA] 1002 - MSAFD Tcpip [TCP/IP] 1003 - MSAFD Tcpip [UDP/IP] 1004 - MSAFD Tcpip [RAW/IP] 1005 - RSVP UDP Service Provider 1006 - RSVP TCP Service Provider 1007 - MSAFD NetBIOS [DeviceNetBT_Tcpip_{F9B0E229-79AD-49F4-AFA5-789B26A7A433}] SEQPACKET 0 1008 - MSAFD NetBIOS [DeviceNetBT_Tcpip_{F9B0E229-79AD-49F4-AFA5-789B26A7A433}] DATAGRAM 0 1009 - MSAFD NetBIOS [DeviceNetBT_Tcpip_{7F588485-D8FD-4384-94F8-20934493A8AC}] SEQPACKET 1 1010 - MSAFD NetBIOS [DeviceNetBT_Tcpip_{7F588485-D8FD-4384-94F8-20934493A8AC}] DATAGRAM 1 1011 - MSAFD NetBIOS [DeviceNetBT_Tcpip_{8500C835-C738-4E3B-910B-2B41B8C628F5}] SEQPACKET 2 1012 - MSAFD NetBIOS [DeviceNetBT_Tcpip_{8500C835-C738-4E3B-910B-2B41B8C628F5}] DATAGRAM 2
Pour réaliser cette souplesse les fonctions sont donc appelées à travers une table nommée WSPPROC_TABLE, ainsi on peut remplacer les adresses des API par les notre et donc manipuler les sockets tranquillement :] Vous pouvez retrouver un exemple d’implémentation ici.
Bon tout ca c’est bien joli. Mais au final send() appel la fonction WSPSend qui va enfin faire la requête au noyau.
kd> kv 0012fd0c 71a55908 00000060 00000038 00000000 ntdll!ZwDeviceIoControlFile+0xc (FPO: [10,0,0]) 0012fd98 71ab42f8 00000060 0012fdd0 00000001 mswsock!WSPSend+0x16c (FPO: [Non-Fpo]) 0012fde0 00400342 00000060 0012ff94 00000013 WS2_32!send+0x82 (FPO: [Non-Fpo]) WARNING: Stack unwind information not available. Following frames may be wrong. 0012ffc0 7c816d4f 00310039 00310037 7ffd8000 rezo+0x342 0012fff0 00000000 00400220 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo])
Le prototype de la fonction NtDeviceIoControlFile est le suivant :
NTSTATUS ZwDeviceIoControlFile( IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength ); mswsock.dll!WSPSend [...] 71A558E8 53 PUSH EBX <-OutputBufferLength 71A558E9 53 PUSH EBX <-OutputBuffer 71A558EA 6A 10 PUSH 10 <-InputBufferLength 71A558EC 8D45 B0 LEA EAX,DWORD PTR SS:[EBP-50] 71A558EF 50 PUSH EAX <-InputBuffer 71A558F0 68 1F200100 PUSH 1201F <-IoControlCode 71A558F5 FF75 D8 PUSH DWORD PTR SS:[EBP-28] <-IoStatusBloc 71A558F8 FF75 D4 PUSH DWORD PTR SS:[EBP-2C] <-ApcContext 71A558FB FF75 DC PUSH DWORD PTR SS:[EBP-24] <-ApcRoutine 71A558FE 56 PUSH ESI <-Event 71A558FF FF75 08 PUSH DWORD PTR SS:[EBP+8] <-FileHandle 71A55902 FF15 E010A571 CALL NEAR DWORD PTR DS:[<&ntdll.NtDevice>; ntdll.ZwDeviceIoControlFile [...]
Pour un send() l’IoControlCode est 0x1201F, WSPSend ne passe qu’un InputBuffer, l’OutputBufferLength étant nul, il n’y aura aucun retour. Il serait intéressant de connaitre ce qui est passé à travers l’InputBuffer. Pour cela, connaissant le prototype de WSPSend :
int WSPSend( IN SOCKET s, IN LPWSABUF lpBuffers, IN DWORD dwBufferCount, OUT LPDWORD lpNumberOfBytesSent, IN DWORD dwFlags, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, IN LPWSATHREADID lpThreadId, OUT LPINT lpErrno ); lpBuffers : Pointer to an array of WSABUF structures. This array must remain valid for the duration of the send operation. dwBufferCount : Number of WSABUF structures at lpBuffers typedef struct _WSABUF { u_long len; char FAR *buf; } WSABUF, FAR * LPWSABUF;
Le paramètre lpBuffers pointe sur une liste de WSABUF, ces derniers contiennent nos datas, pour vérifier il suffit de mater la valeur du pointeur dans la stack juste avant l’appel à NtDeviceIoControlFile :
0012E980 0000005C |Arg1 = 0000005C 0012E984 00000038 |Arg2 = 00000038 0012E988 00000000 |Arg3 = 00000000 0012E98C 00000000 |Arg4 = 00000000 0012E990 0012E9CC |Arg5 = 0012E9CC 0012E994 0001201F |Arg6 = 0001201F 0012E998 0012E9B4 |Arg7 = 0012E9B4 <-InputBuffer 0012E99C 00000010 |Arg8 = 00000010 0012E9A0 00000000 |Arg9 = 00000000 0012E9A4 00000000 Arg10 = 00000000 0012E9B4 8C EA 12 00 01 00 00 00 00 00 00 00 00 00 00 00 ΐ............
L’IntputBuffer pointe sur une structure de 16 bytes, le premier dword est un pointeur sur une liste de WSABUF, le dword suivant contient le nombre d’éléments de la liste. Regardons le contenu du WSABUF.
0012EA8C 13 00 00 00 74 EA 12 00 ...tê. 0012EA74 47 45 54 20 2F 20 48 54 54 50 2F 31 2E 31 0D 0A GET / HTTP/1.1.. 0012EA84 0D 0A 00 00 ....
On a la taille de nos datas (0×13) et un pointeur sur celles-ci. Jusqu’ici rien d’impressionnant, maintenant on voudrait savoir à quel driver va être envoyé l’IRP. Pour cela, il regarde ce que référence le handle passé en tant que premier argument à NtDeviceIoControlFile.
kd> !handle 5C 3 288 processor number 0, process 00000288 Searching for Process with Cid == 288 PROCESS 865e22a8 SessionId: 0 Cid: 0288 Peb: 7ffdf000 ParentCid: 0234 DirBase: 13fd7000 ObjectTable: e18fed48 HandleCount: 24. Image: rezo.exe Handle table at e16e9000 with 24 Entries in use 005c: Object: 866705a0 GrantedAccess: 001f01ff (Inherit) Entry: e16e90b8 Object: 866705a0 Type: (867e9040) File ObjectHeader: 86670588 (old version) HandleCount: 1 PointerCount: 1 Directory Object: 00000000 Name: Endpoint {Afd}
Le handle fait référence au device \Endpoint du driver Afd.sys. Si on regarde bien, on s’aperçoit que cet handle est en fait notre socket, initialisé lors de l’appel à la fonction socket(). Le driver afd (Ancillary Function Driver for WinSock) correspond, d’après ce que j’ai lu, au driver d’émulation des sockets servant à effectuer la gestion des buffers et des connexions afin de les transmettre à la couche inférieure appelé TDI (Transport Driver Interface). Regardons la table des IRP_MX_XXX, j’ajoute que cette table permet en fait aux autres composants du système de comuniquer avec le driver.
kd> !devobj 0x865df770 Device object (865df770) is for: Afd DriverAFD DriverObject 8661b240 Current Irp 00000000 RefCount 40 Type 00000011 Flags 00000050 Dacl e1406284 DevExt 00000000 DevObjExt 865df828 ExtensionFlags (0000000000) Device queue is not busy. kd> !drvobj DriverAFD 3 Driver object (8661b240) is for: DriverAFD Driver Extension List: (id , addr) Device Object list: 865df770 DriverEntry: baf48f40 afd!GsDriverEntry DriverStartIo: 00000000 DriverUnload: baf32482 afd!AfdUnload Dispatch routines: [00] IRP_MJ_CREATE baf36d40 afd!AfdDispatch [01] IRP_MJ_CREATE_NAMED_PIPE baf36d40 afd!AfdDispatch [02] IRP_MJ_CLOSE baf36d40 afd!AfdDispatch [03] IRP_MJ_READ baf36d40 afd!AfdDispatch [04] IRP_MJ_WRITE baf36d40 afd!AfdDispatch [05] IRP_MJ_QUERY_INFORMATION baf36d40 afd!AfdDispatch [06] IRP_MJ_SET_INFORMATION baf36d40 afd!AfdDispatch [07] IRP_MJ_QUERY_EA baf36d40 afd!AfdDispatch [08] IRP_MJ_SET_EA baf36d40 afd!AfdDispatch [09] IRP_MJ_FLUSH_BUFFERS baf36d40 afd!AfdDispatch [0a] IRP_MJ_QUERY_VOLUME_INFORMATION baf36d40 afd!AfdDispatch [0b] IRP_MJ_SET_VOLUME_INFORMATION baf36d40 afd!AfdDispatch [0c] IRP_MJ_DIRECTORY_CONTROL baf36d40 afd!AfdDispatch [0d] IRP_MJ_FILE_SYSTEM_CONTROL baf36d40 afd!AfdDispatch [0e] IRP_MJ_DEVICE_CONTROL baf36280 afd!AfdDispatchDeviceControl [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL baf36d40 afd!AfdDispatch [10] IRP_MJ_SHUTDOWN baf36d40 afd!AfdDispatch [11] IRP_MJ_LOCK_CONTROL baf36d40 afd!AfdDispatch [12] IRP_MJ_CLEANUP baf36d40 afd!AfdDispatch [13] IRP_MJ_CREATE_MAILSLOT baf36d40 afd!AfdDispatch [14] IRP_MJ_QUERY_SECURITY baf36d40 afd!AfdDispatch [15] IRP_MJ_SET_SECURITY baf36d40 afd!AfdDispatch [16] IRP_MJ_POWER baf36d40 afd!AfdDispatch [17] IRP_MJ_SYSTEM_CONTROL baf36d40 afd!AfdDispatch [18] IRP_MJ_DEVICE_CHANGE baf36d40 afd!AfdDispatch [19] IRP_MJ_QUERY_QUOTA baf36d40 afd!AfdDispatch [1a] IRP_MJ_SET_QUOTA baf36d40 afd!AfdDispatch [1b] IRP_MJ_PNP baf36d40 afd!AfdDispatch Fast I/O routines: FastIoRead baf321b2 afd!AfdFastIoRead FastIoWrite baf32291 afd!AfdFastIoWrite FastIoUnlockAll baf353d4 afd!AfdSanFastUnlockAll FastIoDeviceControl baf2d880 afd!AfdFastIoDeviceControl
Ok, on remarque direct que la fonction principale est AfdDispatchDeviceControl, en effet c’est elle qui est chargée de gérer tous les IRP provenant des NtDeviceIoControlFile. Sachant que le format des paramètres des l’IRP est connu lorsque qu’il passe par une major fonction de type XxxDispatchDeviceControl, on peut retrouver facilement nos arguments. Au début, lorsque je mettais un BP sur la fonction AfdDispatchDeviceControl je n’arrivais pas à break après l’appel à WSPSend, je me suis en fait aperçu qu’il existant une fonction de dispatch fonctionnant en fast I/O appelé AfdFastIoDeviceControl. En fait les IRP peuvent être gérées de 2 manières, synchrone et asynchrone, dans le cas synchrone l’IRP est complété par le thread qui la crée, ce qui signifie que si les drivers manipulent des données userland représentées par l’IRP, elles seront accessibles durant tout le processus, typiquement lorsque qu’on utilise une méthode d’I/O de type Neither Buffered Nor Direct I/O. Dans la cas asynchrone, l’IRP peut très bien être complétée dans le contexte d’un autre thread (appartenant ou non au même process) ce qui signifie qu’un pointeur userspace n’est plus valide, il faut donc utilisé un MDL permettant d’accéder au physical pages représentant, on peut, pour cela, procéder par une méthode Buffered I/O ou bien Direct I/O.
Bon notre cas, c’est du Fast I/O, les pointeurs utilisés pour lire nos datas sont donc ceux du userspace. Il suffit de vérifier les arguments passés à AfdFastIoDeviceControl.
// // Fast I/O device control procedure. // typedef BOOLEAN FAST_IO_DEVICE_CONTROL ( __in struct _FILE_OBJECT *FileObject, __in BOOLEAN Wait, __in_opt PVOID InputBuffer, __in ULONG InputBufferLength, __out_opt PVOID OutputBuffer, __in ULONG OutputBufferLength, __in ULONG IoControlCode, __out PIO_STATUS_BLOCK IoStatus, __in struct _DEVICE_OBJECT *DeviceObject ); Breakpoint 1 hit afd!AfdFastIoDeviceControl: f9640880 680c010000 push 10Ch kd> kv ChildEBP RetAddr Args to Child f6300c50 8057fc67 8170d8c8 00000001 0012fd48 afd!AfdFastIoDeviceControl (FPO: [Non-Fpo]) f6300d00 8057fbfa 00000060 00000038 00000000 nt!IopXxxControlFile+0x261 (FPO: [Non-Fpo]) f6300d34 804df06b 00000060 00000038 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) f6300d34 7c90eb94 00000060 00000038 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f6300d64) 0012fd08 7c90d8ef 71a55908 00000060 00000038 ntdll!KiFastSystemCallRet (FPO: [0,0,0]) 0012fd0c 71a55908 00000060 00000038 00000000 ntdll!ZwDeviceIoControlFile+0xc (FPO: [10,0,0]) 0012fd98 71ab42f8 00000060 0012fdd0 00000001 mswsock!WSPSend+0x16c (FPO: [Non-Fpo]) 0012fde0 00400342 00000060 0012ff94 00000013 WS2_32!send+0x82 (FPO: [Non-Fpo]) WARNING: Stack unwind information not available. Following frames may be wrong. 0012ffc0 7c816d4f 00310039 00310037 7ffd4000 rezo+0x342 0012fff0 00000000 00400220 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo]) 0012fd48==InputBuffer, dans le contexte du thread qui a call le NtDeviceIoControlFile
Bon pendant qu’on y est, regardons la fonction chargée de dispatcher les IRP « normales », AfdDispatchDeviceControl:
kd> uf afd!AfdDispatchDeviceControl afd!AfdDispatchDeviceControl: f9632280 8bff mov edi,edi f9632282 55 push ebp f9632283 8bec mov ebp,esp f9632285 8b4d0c mov ecx,dword ptr [ebp+0Ch] ;Irp f9632288 8b5160 mov edx,dword ptr [ecx+60h] f963228b 56 push esi f963228c 57 push edi f963228d 8b7a0c mov edi,dword ptr [edx+0Ch] <;esi=IoControlCode f9632290 8bc7 mov eax,edi f9632292 c1e802 shr eax,2 f9632295 25ff030000 and eax,3FFh f963229a 83f846 cmp eax,46h f963229d 0f834c690000 jae afd!AfdDispatchDeviceControl+0x3d (f9638bef) afd!AfdDispatchDeviceControl+0x1f: f96322a3 8bf0 mov esi,eax f96322a5 c1e602 shl esi,2 f96322a8 39bea09062f9 cmp dword ptr afd!AfdIoctlTable (f96290a0)[esi],edi f96322ae 0f853b690000 jne afd!AfdDispatchDeviceControl+0x3d (f9638bef) afd!AfdDispatchDeviceControl+0x2c: f96322b4 884201 mov byte ptr [edx+1],al f96322b7 8bb6b89162f9 mov esi,dword ptr afd!AfdIrpCallDispatch (f96291b8)[esi] f96322bd 85f6 test esi,esi f96322bf 0f842a690000 je afd!AfdDispatchDeviceControl+0x3d (f9638bef) afd!AfdDispatchDeviceControl+0x39: f96322c5 ffd6 call esi afd!AfdDispatchDeviceControl+0x53: f96322c7 5f pop edi f96322c8 5e pop esi f96322c9 5d pop ebp f96322ca c20800 ret 8 afd!AfdDispatchDeviceControl+0x3d: f9638bef be100000c0 mov esi,0C0000010h f9638bf4 897118 mov dword ptr [ecx+18h],esi f9638bf7 8a15119062f9 mov dl,byte ptr [afd!AfdPriorityBoost (f9629011)] f9638bfd ff158c8562f9 call dword ptr [afd!_imp_IofCompleteRequest (f962858c)] f9638c03 8bc6 mov eax,esi f9638c05 e9bd96ffff jmp afd!AfdDispatchDeviceControl+0x53 (f96322c7)
Déjà on a de la chance, la fonction est relativement simple, elle va prendre notre IoControlCode puis calculer l’indice d’une fonction dans une table appelée AfdIrpCallDispatch.
kd> dps afd!AfdIrpCallDispatch l 90 f96291b8 f962b23a afd!AfdBind f96291bc f962aa43 afd!AfdConnect f96291c0 f9627bff afd!AfdDispatchImmediateIrp f96291c4 f963d5dc afd!AfdWaitForListen f96291c8 f963c053 afd!AfdAccept f96291cc f9634128 afd!AfdReceive f96291d0 f9636833 afd!AfdReceiveDatagram f96291d4 f9636ef2 afd!AfdSend f96291d8 f9640e33 afd!AfdSendDatagram f96291dc f9632a14 afd!AfdPoll f96291e0 f9627bff afd!AfdDispatchImmediateIrp f96291e4 f962b0b9 afd!AfdGetAddress f96291e8 f9627bff afd!AfdDispatchImmediateIrp f96291ec f9627bff afd!AfdDispatchImmediateIrp f96291f0 f9627bff afd!AfdDispatchImmediateIrp f96291f4 f9627bff afd!AfdDispatchImmediateIrp f96291f8 f9627bff afd!AfdDispatchImmediateIrp f96291fc f9627bff afd!AfdDispatchImmediateIrp f9629200 f9627bff afd!AfdDispatchImmediateIrp f9629204 f9627bff afd!AfdDispatchImmediateIrp f9629208 f9627bff afd!AfdDispatchImmediateIrp f962920c f9627bff afd!AfdDispatchImmediateIrp f9629210 f9627bff afd!AfdDispatchImmediateIrp f9629214 f9627bff afd!AfdDispatchImmediateIrp f9629218 f9627bff afd!AfdDispatchImmediateIrp f962921c f9627bff afd!AfdDispatchImmediateIrp f9629220 f9627bff afd!AfdDispatchImmediateIrp f9629224 f9627bff afd!AfdDispatchImmediateIrp f9629228 f9627bff afd!AfdDispatchImmediateIrp f962922c f9627bff afd!AfdDispatchImmediateIrp f9629230 f9627bff afd!AfdDispatchImmediateIrp f9629234 f9630781 afd!AfdTransmitFile f9629238 f9636203 afd!AfdSuperAccept f962923c f9627bff afd!AfdDispatchImmediateIrp f9629240 f9627bff afd!AfdDispatchImmediateIrp f9629244 f963bb7a afd!AfdDeferAccept f9629248 f963d5dc afd!AfdWaitForListen f962924c f963e563 afd!AfdSetQos f9629250 f962e911 afd!AfdGetQos f9629254 f962ede2 afd!AfdNoOperation f9629258 f963f197 afd!AfdValidateGroup f962925c f9627bff afd!AfdDispatchImmediateIrp f9629260 f9627bff afd!AfdDispatchImmediateIrp f9629264 f9627f6d afd!AfdRoutingInterfaceChange f9629268 f9627bff afd!AfdDispatchImmediateIrp f962926c f9635e99 afd!AfdAddressListChange f9629270 f962dc7f afd!AfdJoinLeaf f9629274 00000000 f9629278 f9630c88 afd!AfdTransmitPackets f962927c f962d8c8 afd!AfdSuperConnect f9629280 f96280d9 afd!AfdSuperDisconnect f9629284 f9636833 afd!AfdReceiveDatagram f9629288 f9627bff afd!AfdDispatchImmediateIrp f962928c f9627bff afd!AfdDispatchImmediateIrp f9629290 f9627bff afd!AfdDispatchImmediateIrp f9629294 f9642e24 afd!AfdSanConnectHandler f9629298 f9627bff afd!AfdDispatchImmediateIrp f962929c f9627bff afd!AfdDispatchImmediateIrp f96292a0 f9627bff afd!AfdDispatchImmediateIrp f96292a4 f9627bff afd!AfdDispatchImmediateIrp f96292a8 f9627bff afd!AfdDispatchImmediateIrp f96292ac f9644693 afd!AfdSanAcquireContext f96292b0 f9627bff afd!AfdDispatchImmediateIrp f96292b4 f9627bff afd!AfdDispatchImmediateIrp f96292b8 f9627bff afd!AfdDispatchImmediateIrp f96292bc f9627bff afd!AfdDispatchImmediateIrp f96292c0 f9631af8 afd!AfdSanAddrListChange f96292c4 f963584b afd!AfdSocketCloseNotify f96292c8 f9627bff afd!AfdDispatchImmediateIrp f96292cc f962eead afd!AfdQueryFirewallSocketAddress f96292d0 00000000 f96292d4 00000000 f96292d8 f963649b afd!AfdStartListen f96292dc 00000000 f96292e0 00000000 f96292e4 00000000 f96292e8 00000000 f96292ec 00000000 f96292f0 00000000 f96292f4 00000000 f96292f8 f9635709 afd!AfdPartialDisconnect f96292fc 00000000 f9629300 f9636ca4 afd!AfdQueryReceiveInformation f9629304 f9629e62 afd!AfdQueryHandles f9629308 f963348c afd!AfdSetInformation f962930c f962ecf9 afd!AfdGetRemoteAddress f9629310 f962bb35 afd!AfdGetContext f9629314 f962a22c afd!AfdSetContext f9629318 f963ed8d afd!AfdSetConnectData f962931c f963ed8d afd!AfdSetConnectData f9629320 f963ed8d afd!AfdSetConnectData f9629324 f963ed8d afd!AfdSetConnectData f9629328 f963e9ce afd!AfdGetConnectData f962932c f963e9ce afd!AfdGetConnectData f9629330 f963e9ce afd!AfdGetConnectData f9629334 f963e9ce afd!AfdGetConnectData f9629338 f963ed8d afd!AfdSetConnectData f962933c f963ed8d afd!AfdSetConnectData f9629340 f963ed8d afd!AfdSetConnectData f9629344 f963ed8d afd!AfdSetConnectData f9629348 f962b6cd afd!AfdGetInformation f962934c 00000000 f9629350 00000000 f9629354 f96359c0 afd!AfdEventSelect f9629358 f9635ad2 afd!AfdEnumNetworkEvents f962935c 00000000 f9629360 00000000 f9629364 00000000 f9629368 00000000 f962936c 00000000 f9629370 00000000 f9629374 f963f369 afd!AfdGetUnacceptedConnectData f9629378 f962f93d afd!AfdRoutingInterfaceQuery f962937c 00000000 f9629380 f962bbd3 afd!AfdAddressListQuery f9629384 00000000 f9629388 00000000 f962938c 00000000 f9629390 00000000 f9629394 00000000 f9629398 00000000 f962939c 00000000 f96293a0 f96438f6 afd!AfdSanFastCementEndpoint f96293a4 f9643a8c afd!AfdSanFastSetEvents f96293a8 f9643c2a afd!AfdSanFastResetEvents f96293ac 00000000 f96293b0 f9643d7f afd!AfdSanFastCompleteAccept f96293b4 f96443cb afd!AfdSanFastCompleteRequest f96293b8 f9631261 afd!AfdSanFastCompleteIo f96293bc f9643fe1 afd!AfdSanFastRefreshEndpoint f96293c0 f96312ed afd!AfdSanFastGetPhysicalAddr f96293c4 00000000 f96293c8 f9631c27 afd!AfdSanFastTransferCtx f96293cc f96312fa afd!AfdSanFastGetServicePid f96293d0 f963133a afd!AfdSanFastSetServiceProcess f96293d4 f9631aab afd!AfdSanFastProviderChange f96293d8 00000000 f96293dc 00000000 f96293e0 f962ebdd afd!AfdQueryFirewallSocketInfo f96293e4 00000000 f96293e8 ffffffff f96293ec ffffffff f96293f0 ffffffff f96293f4 ffffffff
Je pense que les noms des fonctions sont assez parlant :]
Revenons à notre AfdFastConnectionSend, je rappel juste la call stack qui nous a mené là :
kd> bp afd!AfdFastConnectionSend kd> g Breakpoint 1 hit afd!AfdFastConnectionSend: f9633da6 8bff mov edi,edi kd> kv ChildEBP RetAddr Args to Child f615cb10 f962a5e5 81603ef0 f615cb9c 00000013 afd!AfdFastConnectionSend (FPO: [Non-Fpo]) f615cc50 8057fc67 815adc18 00000001 0012e9b4 afd!AfdFastIoDeviceControl+0x415 (FPO: [Non-Fpo]) f615cd00 8057fbfa 00000060 00000038 00000000 nt!IopXxxControlFile+0x261 (FPO: [Non-Fpo]) f615cd34 804df06b 00000060 00000038 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) f615cd34 7c90eb94 00000060 00000038 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f615cd64) 0012e974 7c90d8ef 71a55908 00000060 00000038 ntdll!KiFastSystemCallRet (FPO: [0,0,0]) 0012e978 71a55908 00000060 00000038 00000000 ntdll!ZwDeviceIoControlFile+0xc (FPO: [10,0,0]) 0012ea04 71ab6294 00000060 0012ea8c 00000001 mswsock!WSPSend+0x16c (FPO: [Non-Fpo]) *** ERROR: Module load completed but symbols could not be loaded for rezo.exe 0012ea40 00400433 00000060 0012ea8c 00000001 WS2_32!WSASend+0x77 (FPO: [Non-Fpo]) WARNING: Stack unwind information not available. Following frames may be wrong. 0012ffc0 7c816d4f 00310039 00310037 7ffd7000 rezo+0x433 0012fff0 00000000 004002b0 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo])
En observant le disass de AfdFastConnectionSend on peut voir que cette fonction appel le driver suivant, tcpip.sys (w00t on se rapproche de la fin). Voyons ce qu’on peut obtenir comme info sur ce dernier :
kd> !object global??tcp Object: e1468cc0 Type: (817d2408) SymbolicLink ObjectHeader: e1468ca8 (old version) HandleCount: 0 PointerCount: 1 Directory Object: e10012c8 Name: Tcp Target String is 'DeviceTcp' kd> !devobj DeviceTcp Device object (814e3880) is for: Tcp DriverTcpip DriverObject 81520688 Current Irp 00000000 RefCount 227 Type 00000012 Flags 00000050 Dacl e145b9bc DevExt 00000000 DevObjExt 814e3938 ExtensionFlags (0000000000) Device queue is not busy. kd> !drvobj DriverTcpip 3 Driver object (81520688) is for: DriverTcpip Driver Extension List: (id , addr) Device Object list: 814c7bd8 814e3d80 814e3880 8156a920 814cc358 DriverEntry: f96b7bef tcpip!GsDriverEntry DriverStartIo: 00000000 DriverUnload: f96677aa tcpip!ArpUnload Dispatch routines: [00] IRP_MJ_CREATE f9644a3e tcpip!TCPDispatch [01] IRP_MJ_CREATE_NAMED_PIPE f9644a3e tcpip!TCPDispatch [02] IRP_MJ_CLOSE f9644a3e tcpip!TCPDispatch [03] IRP_MJ_READ f9644a3e tcpip!TCPDispatch [04] IRP_MJ_WRITE f9644a3e tcpip!TCPDispatch [05] IRP_MJ_QUERY_INFORMATION f9644a3e tcpip!TCPDispatch [06] IRP_MJ_SET_INFORMATION f9644a3e tcpip!TCPDispatch [07] IRP_MJ_QUERY_EA f9644a3e tcpip!TCPDispatch [08] IRP_MJ_SET_EA f9644a3e tcpip!TCPDispatch [09] IRP_MJ_FLUSH_BUFFERS f9644a3e tcpip!TCPDispatch [0a] IRP_MJ_QUERY_VOLUME_INFORMATION f9644a3e tcpip!TCPDispatch [0b] IRP_MJ_SET_VOLUME_INFORMATION f9644a3e tcpip!TCPDispatch [0c] IRP_MJ_DIRECTORY_CONTROL f9644a3e tcpip!TCPDispatch [0d] IRP_MJ_FILE_SYSTEM_CONTROL f9644a3e tcpip!TCPDispatch [0e] IRP_MJ_DEVICE_CONTROL f9644a3e tcpip!TCPDispatch [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL f9644cc8 tcpip!TCPDispatchInternalDeviceControl [10] IRP_MJ_SHUTDOWN f9644a3e tcpip!TCPDispatch [11] IRP_MJ_LOCK_CONTROL f9644a3e tcpip!TCPDispatch [12] IRP_MJ_CLEANUP f9644a3e tcpip!TCPDispatch [13] IRP_MJ_CREATE_MAILSLOT f9644a3e tcpip!TCPDispatch [14] IRP_MJ_QUERY_SECURITY f9644a3e tcpip!TCPDispatch [15] IRP_MJ_SET_SECURITY f9644a3e tcpip!TCPDispatch [16] IRP_MJ_POWER f9644a3e tcpip!TCPDispatch [17] IRP_MJ_SYSTEM_CONTROL f9644a3e tcpip!TCPDispatch [18] IRP_MJ_DEVICE_CHANGE f9644a3e tcpip!TCPDispatch [19] IRP_MJ_QUERY_QUOTA f9644a3e tcpip!TCPDispatch [1a] IRP_MJ_SET_QUOTA f9644a3e tcpip!TCPDispatch [1b] IRP_MJ_PNP f9644a3e tcpip!TCPDispatch
Ok, notre petit IRP est envoyé à la fonction TCPDispatchInternalDeviceControl qui est chargée de handler les IRP de type IRP_MJ_INTERNAL_DEVICE_CONTROL.
kd> kv ChildEBP RetAddr Args to Child f9bfbaa0 804e3d77 815a0d80 815ff300 815e5738 tcpip!TCPDispatchInternalDeviceControl (FPO: [Non-Fpo]) f9bfbab0 f9633ede 00000000 00000008 f9bfbb10 nt!IopfCallDriver+0x31 (FPO: [0,0,0]) f9bfbb10 f962a5e5 81590918 f9bfbb9c 00000013 afd!AfdFastConnectionSend+0x209 (FPO: [Non-Fpo]) f9bfbc50 8057fc67 8159fbf8 00000001 0012fd48 afd!AfdFastIoDeviceControl+0x415 (FPO: [Non-Fpo]) f9bfbd00 8057fbfa 00000060 00000038 00000000 nt!IopXxxControlFile+0x261 (FPO: [Non-Fpo]) f9bfbd34 804df06b 00000060 00000038 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) f9bfbd34 7c90eb94 00000060 00000038 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f9bfbd64) 0012fd08 7c90d8ef 71a55908 00000060 00000038 ntdll!KiFastSystemCallRet (FPO: [0,0,0]) 0012fd0c 71a55908 00000060 00000038 00000000 ntdll!ZwDeviceIoControlFile+0xc (FPO: [10,0,0]) 0012fd98 71ab42f8 00000060 0012fdd0 00000001 mswsock!WSPSend+0x16c (FPO: [Non-Fpo]) 0012fde0 00400342 00000060 0012ff94 00000013 WS2_32!send+0x82 (FPO: [Non-Fpo]) WARNING: Stack unwind information not available. Following frames may be wrong. 0012ffc0 7c816d4f 00310039 00310037 7ffde000 rezo+0x342 0012fff0 00000000 00400220 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo])
Si on regarde un peu l’IRP qui est passé au driver tcpip.sys, on peut voir :
kd> !irp 815ff300 Irp is active with 3 stacks 3 is current (= 0x815ff3b8) Mdl=815ff260: No System Buffer: Thread 00000000: Irp stack trace. Pending has been returned cmd flg cl Device File Completion-Context [ 0, 0] 0 0 00000000 00000000 00000000-00000000 Args: 00000000 00000000 00000000 00000000 [ 0, 0] 0 0 00000000 00000000 00000000-00000000 Args: 00000000 00000000 00000000 00000000 >[ f, 7] 0 e0 815a0d80 815a77b8 f9633d47-815ff228 Success Error Cancel DriverTcpip afd!AfdRestartBufferSend Args: 00000013 00000000 00000000 00000000
Dans les arguments, la taille de nos datas et si on dump la mémoire référencé par le MDL :
kd> dt nt!_MDL 815ff260 +0x000 Next : (null) +0x004 Size : 32 +0x006 MdlFlags : 4 +0x008 Process : (null) +0x00c MappedSystemVa : 0x815ff280 +0x010 StartVa : 0x815ff000 +0x014 ByteCount : 0x13 +0x018 ByteOffset : 0x280 kd> db 0x815ff280 815ff280 47 45 54 20 2f 20 48 54-54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1.. 815ff290 0d 0a
On retrouve toujours nos petites datas qui voyagent tranquillement dans le noyau. Pour la suite, je ne me suis pas amusé à tracer, analyser le driver tcpip (351 ko !) avec IDA et vous comprendrez À partir de là, on y va full instinct et on met des BP un peu partout ! ET ça marche, il suffit de choisir les fonctions avec les bons noms. Alors arrivé dans le driver NDIS (Network Driver Interface Specification) on a cette call stack :
Breakpoint 1 hit NDIS!ndisMSend: f98a3d33 8bff mov edi,edi kd> kv ChildEBP RetAddr Args to Child f9acb788 f97b5528 8163e248 8179c310 8179c2d8 NDIS!ndisMSend (FPO: [Non-Fpo]) f9acb7c4 f988d985 8163caa8 8179c310 00000002 psched!MpSend+0x706 (FPO: [Non-Fpo]) f9acb7ec f964cd00 81699858 8179c310 815b9cc8 NDIS!ndisMSendX+0x1d6 (FPO: [Non-Fpo]) f9acb814 f964c8ce 815b9cc8 8179c310 81673160 tcpip!ARPSendData+0x198 (FPO: [Non-Fpo]) f9acb840 f964c70a 815b9cc8 f9acb800 00000001 tcpip!ARPTransmit+0x193 (FPO: [Non-Fpo]) f9acb870 f964c4ad 8159b4b0 0101a8c0 8179c310 tcpip!SendIPPacket+0x18e (FPO: [Non-Fpo]) f9acb9bc f9664427 f968a4b8 81558a28 815589c0 tcpip!IPTransmit+0x2859 (FPO: [Non-Fpo]) f9acba28 f96647b5 2ccbca7c 00000000 815fa3b8 tcpip!TCPSend+0x5d8 (FPO: [Non-Fpo]) f9acba50 f9663d97 00000001 00000000 00000000 tcpip!TdiSend+0x1cc (FPO: [Non-Fpo]) f9acba84 f9665977 815fa300 8159a3e4 815fa238 tcpip!TCPSendData+0x83 (FPO: [Non-Fpo]) f9acbaa0 804e3d77 816a9030 815fa300 81554430 tcpip!TCPDispatchInternalDeviceControl+0x51 (FPO: [Non-Fpo]) f9acbab0 f960bede 00000000 00000008 f9acbb10 nt!IopfCallDriver+0x31 (FPO: [0,0,0]) 8167e130 8168f778 00000012 f9649000 00057a80 afd!AfdFastConnectionSend+0x209 (FPO: [Non-Fpo])
Remarquez que le packet a traversé la couche TDI (Transport Dispatch Interface) qu’on peut situer sur le schéma suivant :
Et là, grand bonheur, si on utilise la commande !ndiskd.pkt sur le second argument de la fonction ndisMsend on peut voir !
kd> !pkt 8179c310 5 NDIS_PACKET at 8179c310 MDL = 81511448 StartVa ffffffff81511000, ByteCount 0xe, ByteOffset 0x468, NB MdlOffset 0x0 81511468: 00 06 5b 39 5b b9 00 03 ff 6c d1 53 08 00 MDL = 815122c4 StartVa ffffffff81512000, ByteCount 0x14, ByteOffset 0x2e4, NB MdlOffset 0x0 815122e4: 45 00 00 3b 01 c5 40 00 80 06 dd b6 c0 a8 01 dc 815122f4: d1 55 87 67 MDL = 815589c0 StartVa ffffffff81558000, ByteCount 0x14, ByteOffset 0xa00, NB MdlOffset 0x0 81558a00: 04 28 00 50 2c cb ca 7c 50 74 0a eb 50 18 ff ff 81558a10: 5e b8 00 00 MDL = 815fa3dc StartVa ffffffff815fa000, ByteCount 0x13, ByteOffset 0x280, NB MdlOffset 0x0 815fa280: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a 815fa290: 0d 0a 00 0012EA74 47 45 54 20 2F 20 48 54 54 50 2F 31 2E 31 0D 0A GET / HTTP/1.1.. 0012EA84 0D 0A 00 00 ....
HOO le joli packet, avec toutes ses couches, ethernet, IP, TCP et les datas. Si c’est pas beau tout ça :] Mais évidemment, rien n’est fini, le packet n’a toujours pas été transmis au driver de la carte réseau. Avant cela ndisMSend va mettre dans une liste d’attente notre packet avec la fonction ndisMQueueWorkItem, les packets seront pris en compte plus tard lors de la prise en charge de la liste des DPC.
kd> kv ChildEBP RetAddr Args to Child f9e67f68 f98a3a6e 81639000 81637f30 00000000 dc21x4!DC21X4Send (FPO: [Non-Fpo]) f9e67f94 f98a7f0f 00000000 81678590 81639008 NDIS!ndisMStartSends+0xd7 (FPO: [Non-Fpo]) f9e67fb8 f98a975b 10b8cbb0 00000005 ffdff000 NDIS!ndisMProcessDeferred+0x39 (FPO: [Non-Fpo]) f9e67fd0 804dc179 8163901c 81639008 00000000 NDIS!ndisMDpc+0x148 (FPO: [Non-Fpo]) f9e67ff4 804dbe2d f62f985c 00000000 00000000 nt!KiRetireDpcList+0x46 (FPO: [0,0,0]) f9e67ff8 f62f985c 00000000 00000000 00000000 nt!KiDispatchInterrupt+0x2a (FPO: [Uses EBP] [0,0,1])
Le bout de code intéressant de DC21X4Send faisant partie du driver DC21X4.sys qui est le NDIS 5.0 DC21X4 miniport driver de virtual PC est :
push 1 ; Value push dword ptr [esi+234h] ; Port call ds:__imp__WRITE_PORT_ULONG@8 ; WRITE_PORT_ULONG(x,x)
Le call à WRITE_PORT_ULONG va faire appel au hal :
in hal.dll ; ULONG __stdcall READ_PORT_ULONG(PULONG Port) public _READ_PORT_ULONG@4 _READ_PORT_ULONG@4 proc near Port= dword ptr 4 mov edx, [esp+Port] in eax, dx retn 4 _READ_PORT_ULONG@4 endp
Pour enfin dire au bon I/O port de la carte réseau qu’un packet est prèt à être envoyé.
Voilà, c’est fini, j’ai gagné un bon mal de crâne, mais j’ai à peu près compris comment sont agencés les différentes couches réseau sous Windows. Même si j’ai un peu bâclé la fin, j’espère que cela vous inspira pour faire mumuse avec votre OS préféré
Quelques liens en vrac :
http://msdn2.microsoft.com/en-us/library/ms740650.aspx
http://www.microsoft.com/msj/0599/LayeredService/LayeredService.aspx
http://mi.cnrs-orleans.fr/Security/Win2k/TCPIP/Win2k_TCPIP1.htm
http://2005.recon.cx/recon2005/papers/Jonathan_Levin/The%20Dark%20Side%20of%20Winsock.pdf
http://www.microsoft.com/msj/0599/LayeredService/LayeredService.aspx
http://en.wikipedia.org/wiki/Winsock
http://fr.wikipedia.org/wiki/Ancillary_Function_Driver
http://www.codeproject.com/system/driverdev2.asp
http://www.codeproject.com/system/driverdev5asp.asp
http://en.wikipedia.org/wiki/Transport_Dispatch_Interface
http://en.wikipedia.org/wiki/Network_Driver_Interface_Specification
9 comments juillet 10th, 2007