我正在使用NtDeviceIoControlFile
控制代码调用IOCTL_TCP_QUERY_INFORMATION_EX
,但是在执行实际调用之前,我需要获取输出缓冲区的大小,以便可以为其分配适当的大小。
这是我的代码:
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;
问题是第一次调用
NtDeviceIoControlFile
返回ERROR_INVALID_PARAMETER (87)
。使用SYNCHRONIZE
标志设置打开TCP设备对象的句柄。问题是为什么,在哪里?
最佳答案
#include <tdiinfo.h>
#include <tcpioctl.h>
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<PUNICODE_STRING>(&ObjectName), OBJ_CASE_INSENSITIVE };
HANDLE hFile;
IO_STATUS_BLOCK iosb;
status = NtOpenFile(&hFile, SYNCHRONIZE,
const_cast<POBJECT_ATTRIBUTES>(&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;
}
和输出
{ 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 }
然后我们可以从输出数组中获取具体的
TDIEntityID
,将其复制到TCP_REQUEST_QUERY_INFORMATION_EX
并对此实体进行详细请求,如下所述-https://msdn.microsoft.com/en-us/library/bb432313(v=vs.85).aspx关于c - NtDeviceIoControlFile-获取缓冲区的大小,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46531833/