NtDeviceIoControlFile – Ottenere dimensioni del buffer

Sto chiamando NtDeviceIoControlFile con il codice di controllo IOCTL_TCP_QUERY_INFORMATION_EX , ma prima di eseguire la chiamata vera, ho bisogno di ottenere la dimensione del buffer di output in modo da poter allocare una dimensione appropriata per esso.

Ecco il mio codice:

  TCP_REQUEST_QUERY_INFORMATION_EX TcpRequestQuery; IO_STATUS_BLOCK StatusBlock; DWORD BufferSize = sizeof(TDIENTITYID) * 4096; memset(&TcpRequestQuery, 0, sizeof(TcpRequestQuery)); TcpRequestQuery.ID.toi_class = 0x100; TcpRequestQuery.ID.toi_type = 0x100; TcpRequestQuery.ID.toi_id = 0; TcpRequestQuery.ID.toi_entity.tei_entity = 0; TcpRequestQuery.ID.toi_entity.tei_instance = 0; *EntityList = (TDIENTITYID *) GlobalAlloc (GMEM_ZEROINIT, BufferSize); NTSTATUS Status = NtDeviceIoControlFile( TcpFile, NULL, NULL, NULL, &IOBlock, IOCTL_TCP_QUERY_INFORMATION_EX, &TcpQueryInfo, sizeof(TcpQueryInfo), *EntityList, BufferSize); if (!NT_SUCCESS(Status)) return Status; BufferSize = StatusBlock.uInformation; 

Il problema è che la prima chiamata a NtDeviceIoControlFile restituisce ERROR_INVALID_PARAMETER (87) . L’handle per l’object dispositivo TCP viene aperto con il flag impostato SYNCHRONIZE .

La domanda è: perché e dove?

 #include  #include  NTSTATUS QueryTcp() { NTSTATUS status; #ifndef _WIN64 struct TCP_REQUEST_QUERY_INFORMATION_EX_WOW { TDIObjectID ID; // object ID to query. ULONG pad; // ! for wow64 only - Context must be aligned on 8 byte in 64bit windows uchar Context[CONTEXT_SIZE]; // multi-request context. Zeroed }; PVOID Wow; status = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &Wow, sizeof(Wow), 0); if (0 > status) { return status; } #endif static const UNICODE_STRING ObjectName = RTL_CONSTANT_STRING(L"\\device\\tcp"); static const OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast(&ObjectName), OBJ_CASE_INSENSITIVE }; HANDLE hFile; IO_STATUS_BLOCK iosb; status = NtOpenFile(&hFile, SYNCHRONIZE, const_cast(&oa), &iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT); if (0 <= status) { PVOID InputBuffer; ULONG InputBufferLength; #ifndef _WIN64 if (Wow) { TCP_REQUEST_QUERY_INFORMATION_EX_WOW req = { { { GENERIC_ENTITY }, INFO_CLASS_GENERIC, INFO_TYPE_PROVIDER, ENTITY_LIST_ID } }; InputBuffer = &req, InputBufferLength = sizeof(req); } else #endif { TCP_REQUEST_QUERY_INFORMATION_EX req = { { { GENERIC_ENTITY }, INFO_CLASS_GENERIC, INFO_TYPE_PROVIDER, ENTITY_LIST_ID } }; InputBuffer = &req, InputBufferLength = sizeof(req); } union { PVOID buf; TDIEntityID* pEntity; }; volatile static UCHAR guz; PVOID stack = alloca(guz); ULONG cbAllocated = 0, cbNeed = 8 * sizeof(TDIEntityID); do { if (cbAllocated < cbNeed) { cbAllocated = RtlPointerToOffset(buf = alloca(cbNeed - cbAllocated), stack); } if (0 <= (status = NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_TCP_QUERY_INFORMATION_EX, InputBuffer, InputBufferLength, buf, cbAllocated))) { if (ULONG n = (ULONG)iosb.Information / sizeof(TDIEntityID)) { do { DbgPrint("{ %08x, %08x }\n", pEntity->tei_entity, pEntity->tei_instance); } while (pEntity++, --n); } } cbNeed += 8 * sizeof(TDIEntityID); } while (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL); NtClose(hFile); } return status; } 

e uscita

 { 00000400, 00000000 } { 00000401, 00000000 } { 00000301, 00000000 } { 00000301, 00000001 } { 00000380, 00000000 } { 00000380, 00000001 } { 00000200, 00000015 } { 00000200, 00000014 } { 00000200, 00000013 } { 00000200, 00000012 } { 00000200, 00000011 } { 00000200, 00000010 } { 00000200, 0000000f } { 00000200, 0000000e } { 00000200, 0000000d } 

quindi possiamo ottenere TDIEntityID concreto TDIEntityID di output, copiarlo su TCP_REQUEST_QUERY_INFORMATION_EX e fare richiesta di dettaglio su questa entity framework, come descritto qui – https://msdn.microsoft.com/en-us/library/bb432313(v=vs.85) aspx