Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
NtDeviceIoControlFile-获取缓冲区大小_C_Winapi_Tcp - Fatal编程技术网

NtDeviceIoControlFile-获取缓冲区大小

NtDeviceIoControlFile-获取缓冲区大小,c,winapi,tcp,C,Winapi,Tcp,我正在使用IOCTL\u TCP\u QUERY\u INFORMATION\u EX控制代码调用NtDeviceIoControlFile,但在执行实际调用之前,我需要获取输出缓冲区的大小,以便为其分配适当的大小 这是我的密码: TCP_REQUEST_QUERY_INFORMATION_EX TcpRequestQuery; IO_STATUS_BLOCK StatusBlock; DWORD BufferSize = sizeof(TDIENTITYID) * 40

我正在使用
IOCTL\u TCP\u QUERY\u INFORMATION\u EX
控制代码调用
NtDeviceIoControlFile
,但在执行实际调用之前,我需要获取输出缓冲区的大小,以便为其分配适当的大小

这是我的密码:

    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\u INVALID\u参数(87)
。TCP设备对象的句柄正在使用
SYNCHRONIZE
标志集打开

问题是为什么,在哪里

#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;
}

然后,我们可以从输出数组中获取具体的
tdentityid
,将其复制到
TCP\u REQUEST\u QUERY\u INFORMATION\u EX
,并对该实体进行详细请求,如下所述-

TCP设备对象的句柄正在使用
SYNCHRONIZE
标志集打开,等等<代码>同步这不是标志,而是对设备的期望访问。您可能想使用
文件\u同步\u IO\u非警报
选项?如果您使用它-文件上的所有操作都是同步执行的,您永远不会获得挂起状态,也不需要自己等待。另外,如果您想在请求之后等待,则需要同步句柄。异步句柄只有在您不在请求后等待,而是在回调中处理它完成时才有意义。但是
错误\u无效\u参数
,因为输出缓冲区为0。例如,如何使用此ioctl-因此您需要分配一些输出缓冲区,并将此缓冲区和大小传递给
NtDeviceIoControlFile
。如果缓冲区不够大-出现
STATUS\u buffer\u溢出
STATUS\u buffer\u太小
STATUS\u INFO\u LENGTH\u MISMATCH
-在这种情况下,需要重新分配缓冲区。在某些情况下,请求的缓冲区大小返回小缓冲区的第一个字节(仅在
状态\u buffer\u溢出
的情况下,取决于具体的输出结构)。如果未返回缓冲区大小-您需要自己以某种方式增加它。@RbMm我将问题编辑为示例中的代码,但我甚至无法检查缓冲区是否太小,因为输出仍然是
ERROR\u INVALID\u参数
以及为什么使用
0x100?使用此选项时代码不可读。包括tdiinfo.h和使用
INFO\u CLASS\u GENERIC
INFO\u TYPE\u PROVIDER
或您想要使用的东西?我感谢您的工作和一切,但即使使用了您的代码,我仍然在
状态下获得
c000000d
。“那可能只是我的系统出了问题,我迷路了。”它是从键盘开始的——我不这么认为。你的代码中肯定有错误。我怀疑你是否把我的代码1编译成了1。我打开了一个新项目,把你的代码放在那里进行测试,结果它返回了
c00000d
man,毫无疑问,它就是不起作用。老实说。@itstartedwithkeyboards-上传测试exe并粘贴link@itstartedwithkeyboards-这是因为您的exe不是本机的-在64位windows上32位失败。如果将其构建为64位代码,则不会出现错误。对于32位需要另一个结构使用
{ 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 }