首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关于注册环缓冲区的wintun:ERROR_INVALID_PARAMETER

关于注册环缓冲区的wintun:ERROR_INVALID_PARAMETER
EN

Stack Overflow用户
提问于 2020-07-01 05:32:35
回答 3查看 613关注 0票数 1

目前,我正试图让wintun驱动程序使用我的程序进行简单的隧道操作(参见:https://www.wintun.net/ )。

我成功地找到并打开了网络设备,但是当涉及到注册缓冲区时,我得到了结果ERROR_INVALID_PARAMETER (87)。就像我说的,打开工作很好,注册是用SYSTEM特权完成的(如果没有完成,我就得到ERROR_ACCESS_DENIED (5))。

第一次尝试是malloc环缓冲区,但在那之后,我看了OpenVPN是如何做到的(是的,它增加了wintun支持),它们似乎与CreateFileMapping有关。

首先,这是我的结构:

代码语言:javascript
复制
typedef struct _TUN_RING {
    volatile ULONG Head;
    volatile ULONG Tail;
    volatile LONG Alertable;
    UCHAR Data[(1024 * 1024) + 0x10000];
} TUN_RING;

这是根据文档(https://git.zx2c4.com/wintun/about/节“环形布局”),也是一样的OpenVPN做的。

之后,创建文件映射。

代码语言:javascript
复制
send_ring_handle_ = CreateFileMapping(INVALID_HANDLE_VALUE,
                                            nullptr,
                                            PAGE_READWRITE,
                                            0,
                                            sizeof(TUN_RING),
                                            nullptr);
recv_ring_handle_ = CreateFileMapping(INVALID_HANDLE_VALUE,
                                            nullptr,
                                            PAGE_READWRITE,
                                            0,
                                            sizeof(TUN_RING),
                                            nullptr);

然后创建映射:

代码语言:javascript
复制
send_ring_ = (TUN_RING *)MapViewOfFile(send_ring_handle_,
                                         FILE_MAP_ALL_ACCESS,
                                         0,
                                         0,
                                         sizeof(TUN_RING));
recv_ring_ = (TUN_RING *)MapViewOfFile(recv_ring_handle_,
                                         FILE_MAP_ALL_ACCESS,
                                         0,
                                         0,
                                         sizeof(TUN_RING));

最后(在模拟系统用户之后)尝试向DeviceIoControl注册它

代码语言:javascript
复制
    TUN_REGISTER_RINGS reg_rings;
    memset(&reg_rings, 0, sizeof(TUN_REGISTER_RINGS));
    reg_rings.Send.RingSize = sizeof(TUN_RING);
    reg_rings.Send.Ring = send_ring_;
    reg_rings.Send.TailMoved = CreateEvent(0, TRUE, FALSE, 0);
    reg_rings.Receive.RingSize = sizeof(TUN_RING);
    reg_rings.Receive.Ring = recv_ring_;
    reg_rings.Receive.TailMoved = CreateEvent(0, TRUE, FALSE, 0);

    DWORD len;
    if (!DeviceIoControl(tun_fd_,
                            TUN_IOCTL_REGISTER_RINGS,
                            &reg_rings,
                            sizeof(reg_rings),
                            nullptr,
                            0,
                            &len,
                            nullptr))
    {
        printf("Could not register ring buffers (%d).", ::GetLastError());
        return false;
    }

有人能指指我哪里错了吗?正如我所说,使用malloc而不是文件映射相同的错误变量。

到目前为止,我已经编写了一个使用malloc的完整示例

代码语言:javascript
复制
#include <windows.h>
#include <winioctl.h>
#include <IPHlpApi.h>
#include <ndisguid.h>
#include <TlHelp32.h>
#include <tchar.h>
#include <securitybaseapi.h>
#include <cfgmgr32.h>

#include <stdint.h>
#include <stdio.h>
#include <string>
#include <assert.h>

#pragma pack(push, 1)
typedef struct _TUN_PACKET_PROTO {
    ULONG Size;
    UCHAR Data[]; // max packet size as defined by the driver.
} TUN_PACKET_PROTO;

typedef struct _TUN_RING_PROTO {
    volatile ULONG Head;
    volatile ULONG Tail;
    volatile LONG Alertable;
    UCHAR Data[];
} TUN_RING_PROTO;


#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)

#define WINTUN_RING_CAPACITY        0x800000
#define WINTUN_RING_TRAILING_BYTES  0x10000
#define WINTUN_MAX_PACKET_SIZE      0xffff
#define WINTUN_PACKET_ALIGN         4

/* Memory alignment of packets and rings */
#define TUN_ALIGNMENT sizeof(ULONG)
#define TUN_ALIGN(Size) (((ULONG)(Size) + ((ULONG)TUN_ALIGNMENT - 1)) & ~((ULONG)TUN_ALIGNMENT - 1))
#define TUN_IS_ALIGNED(Size) (!((ULONG)(Size) & ((ULONG)TUN_ALIGNMENT - 1)))
/* Maximum IP packet size */
#define TUN_MAX_IP_PACKET_SIZE 0xFFFF
/* Maximum packet size */
#define TUN_MAX_PACKET_SIZE TUN_ALIGN(sizeof(TUN_PACKET_PROTO) + TUN_MAX_IP_PACKET_SIZE)
/* Minimum ring capacity. */
#define TUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */
/* Maximum ring capacity. */
#define TUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */
/* Calculates ring capacity */
#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING_PROTO) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
/* Calculates ring offset modulo capacity */
#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1))

#define IS_POW2(x) ((x) && !((x) & ((x)-1)))



typedef struct _TUN_RING {
    volatile ULONG Head;
    volatile ULONG Tail;
    volatile LONG Alertable;
    UCHAR Data[WINTUN_RING_CAPACITY + (TUN_MAX_PACKET_SIZE-TUN_ALIGNMENT)];
} TUN_RING;

typedef struct _TUN_PACKET {
    ULONG Size;
    UCHAR Data[WINTUN_MAX_PACKET_SIZE]; // max packet size as defined by the driver.
} TUN_PACKET;

typedef struct _TUN_REGISTER_RINGS {
    struct {
        ULONG RingSize;
        TUN_RING *Ring;
        HANDLE TailMoved;
    } Send, Receive;
} TUN_REGISTER_RINGS;
#pragma pack(pop)

class regkey_t
{
public:
    regkey_t(void);
    regkey_t(HKEY handle);
    ~regkey_t(void);

    void attach(HKEY handle);
    void release(void);

    HKEY detach(void);
    operator HKEY (void) const;
    HKEY &get(void);
    HKEY *operator &(void);

private:
    regkey_t(const regkey_t &);
    regkey_t &operator = (const regkey_t &);

    HKEY handle_;
};

regkey_t::regkey_t():
    handle_(0)
{
}

regkey_t::regkey_t(HKEY handle):
    handle_(handle)
{
}

regkey_t::~regkey_t(void)
{
    release();
}

void regkey_t::attach(HKEY handle)
{
    release();
    handle_ = handle;
}

void regkey_t::release(void)
{
    if (handle_)
    {
        const LONG res (::RegCloseKey(handle_));
        if (res != ERROR_SUCCESS)
        {
            printf("Couldn't close a reg handle (%lu).\n", res);
        }

        handle_ = 0;
    }
}

HKEY regkey_t::detach(void)
{
    const HKEY result (handle_);
    handle_ = 0;
    return result;
}

HKEY &regkey_t::get(void)
{
    return handle_;
}

HKEY *regkey_t::operator &(void)
{
    return &handle_;
}

regkey_t::operator HKEY(void) const
{
    return handle_;
}

bool impersonate_as_system()
{
    HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token;
    PROCESSENTRY32 entry;
    BOOL ret;
    DWORD pid = 0;
    TOKEN_PRIVILEGES privileges;

    ::memset(&entry, 0, sizeof(entry));
    ::memset(&privileges, 0, sizeof(privileges));

    entry.dwSize = sizeof(PROCESSENTRY32);

    privileges.PrivilegeCount = 1;
    privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
    {
        return false;
    }

    if (!ImpersonateSelf(SecurityImpersonation))
    {
        return false;
    }

    if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
    {
        RevertToSelf();
        return false;
    }
    if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
    {
        CloseHandle(thread_token);
        RevertToSelf();
        return false;
    }
    CloseHandle(thread_token);

    process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (process_snapshot == INVALID_HANDLE_VALUE)
    {
        RevertToSelf();
        return false;
    }
    for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry))
    {
        if (::strcmp(entry.szExeFile, "winlogon.exe") == 0)
        {
            pid = entry.th32ProcessID;
            break;
        }
    }
    CloseHandle(process_snapshot);
    if (!pid)
    {
        RevertToSelf();
        return false;
    }

    winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!winlogon_process)
    {
        RevertToSelf();
        return false;
    }

    if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
    {
        CloseHandle(winlogon_process);
        RevertToSelf();
        return false;
    }
    CloseHandle(winlogon_process);

    if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token))
    {
        CloseHandle(winlogon_token);
        RevertToSelf();
        return false;
    }
    CloseHandle(winlogon_token);

    if (!SetThreadToken(NULL, duplicated_token))
    {
        CloseHandle(duplicated_token);
        RevertToSelf();
        return false;
    }
    CloseHandle(duplicated_token);

    return true;
}

std::string get_instance_id(uint32_t device_index)
{
    const std::string key_name("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");

    std::string device_id("");

    regkey_t adapters;
    DWORD ret = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_name.c_str(), 0, KEY_READ, &adapters);
    if (ret != ERROR_SUCCESS)
    {
        printf("Could not open registry key %s (%d).\n", key_name.c_str(), ret);

        return device_id;
    }

    DWORD sub_keys(0);
    ret = ::RegQueryInfoKey(adapters, NULL, NULL, NULL, &sub_keys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    if (ret != ERROR_SUCCESS)
    {
        printf("Could not get info from %s (%d).\n", key_name.c_str(), ret);
        return device_id;
    }

    if (sub_keys <= 0)
    {
        printf("Wrong registry key %s.\n", key_name.c_str());
        return device_id;
    }

    if (device_index >= sub_keys)
    {
        return device_id;
    }

    uint32_t index(0);
    for (DWORD i = 0; i < sub_keys; i++)
    {
        const uint32_t max_key_length = 255;
        TCHAR key[max_key_length];
        DWORD keylen(max_key_length);

        // Get the adapter name
        ret = ::RegEnumKeyEx(adapters, i, key, &keylen, NULL, NULL, NULL, NULL);
        if (ret != ERROR_SUCCESS)
        {
            continue;
        }

        // Append it to NETWORK_ADAPTERS and open it
        regkey_t device;
        const std::string new_key(key_name + "\\" + std::string(key));

        ret = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, new_key.c_str(), 0, KEY_READ, &device);
        if (ret != ERROR_SUCCESS)
        {
            continue;
        }

        TCHAR data[256];
        DWORD len(sizeof(data));
        ret = ::RegQueryValueEx(device, "ComponentId", NULL, NULL, (LPBYTE)data, &len);
        if (ret != ERROR_SUCCESS)
        {
            continue;
        }

        std::string device_name("wintun");
        if (::_tcsnccmp(data, device_name.c_str(), sizeof(TCHAR) * device_name.length()) == 0)
        {
            if (device_index != index)
            {
                index++;
                continue;
            }

            DWORD type;
            len = sizeof(data);

            ret = ::RegQueryValueEx(device, "DeviceInstanceID", NULL, &type, (LPBYTE)data, &len);
            if (ret != ERROR_SUCCESS)
            {
                printf("Could not get info from %s (%d).\n", key_name.c_str(), ret);

            }

            device_id = data;
            break;
        }
    }

    return device_id;
}

bool open_tun_device()
{
    HANDLE tun_fd_ = INVALID_HANDLE_VALUE;
    std::string device_id;
    uint32_t device_index;
    {
        TCHAR *interface_list = nullptr;
        for (device_index = 0; device_index < 256; ++device_index)
        {
            device_id = get_instance_id(device_index);
            if (device_id.empty())
            {
                continue;
            }

            CONFIGRET status = CR_SUCCESS;

            // This loop is recommended as "robust code" by MSDN. See the Remarks of CM_Get_Device_Interface_list.
            do
            {
                DWORD required_chars(0);
                if ((status = ::CM_Get_Device_Interface_List_Size(&required_chars,
                                                        (LPGUID)&GUID_DEVINTERFACE_NET,
                                                        (char *)device_id.c_str(),
                                                        CM_GET_DEVICE_INTERFACE_LIST_PRESENT)) != CR_SUCCESS || !required_chars)
                {
                    break;
                }

                assert(required_chars > 0);
                interface_list = (TCHAR *)::malloc(sizeof(TCHAR) * required_chars);

                status = ::CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_NET,
                                                                  (char *)device_id.c_str(),
                                                                  interface_list,
                                                                  required_chars,
                                                                  CM_GET_DEVICE_INTERFACE_LIST_PRESENT);

                if (status == CR_SUCCESS)
                {
                    break;
                }

                ::free(interface_list);
                interface_list = nullptr;
            } while(status == CR_BUFFER_SMALL);

            if (interface_list)
            {
                break;
            }
        }

        if (!interface_list)
        {
            printf("Could not find wintun interface.\n");
            return false;
        }
        else
        {
            tun_fd_ = ::CreateFile(interface_list,
                                   GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                   nullptr,
                                   OPEN_EXISTING, 0, nullptr);
        }


        ::free(interface_list);
    }

    if (!tun_fd_ || tun_fd_ == INVALID_HANDLE_VALUE)
    {
        printf("Could not open wintun device.\n");
        return false;
    }

    printf("Opened wintun device.\n");
    ::Sleep(1000);

    TUN_RING * send_ring_ = (TUN_RING *)::malloc(sizeof(TUN_RING));
    TUN_RING * recv_ring_ = (TUN_RING *)::malloc(sizeof(TUN_RING));

    if (!recv_ring_ || !send_ring_)
    {
        printf("Could not malloc.\n");
        return false;
    }

    ::memset(send_ring_, 0, sizeof(*send_ring_));
    ::memset(recv_ring_, 0, sizeof(*recv_ring_));

    recv_ring_->Alertable = TRUE;
    recv_ring_->Head = 0;
    recv_ring_->Tail = 0;
    send_ring_->Alertable = TRUE;
    send_ring_->Head = 0;
    send_ring_->Tail = 0;

    HANDLE send_event = ::CreateEvent(0, FALSE, FALSE, 0);
    HANDLE recv_event = ::CreateEvent(0, FALSE, FALSE, 0);
    // register the rings
    if (impersonate_as_system())
    {
        TUN_REGISTER_RINGS reg_rings;
        ::memset(&reg_rings, 0, sizeof(TUN_REGISTER_RINGS));
        reg_rings.Send.RingSize = sizeof(TUN_RING);
        reg_rings.Send.Ring = send_ring_;
        reg_rings.Send.TailMoved = send_event;
        reg_rings.Receive.RingSize = sizeof(TUN_RING);
        reg_rings.Receive.Ring = recv_ring_;
        reg_rings.Receive.TailMoved = recv_event;


        int send_capacity = TUN_RING_CAPACITY(reg_rings.Send.RingSize);

        if ((send_capacity < TUN_MIN_RING_CAPACITY || send_capacity > TUN_MAX_RING_CAPACITY ||
             !IS_POW2(send_capacity) || !reg_rings.Send.TailMoved || !reg_rings.Send.Ring))
        {
            printf("Fuck this shit I am out...\n");
        }


        DWORD len;

        DWORD fuckyou = 0;
        if (!::DeviceIoControl(tun_fd_, TUN_IOCTL_FORCE_CLOSE_HANDLES,
                               &fuckyou, sizeof(fuckyou), nullptr, 0, &len, nullptr))
        {
            printf("Error releasing handles (%d).\n", ::GetLastError());
        }


        if (!::DeviceIoControl(tun_fd_,
                                TUN_IOCTL_REGISTER_RINGS,
                                &reg_rings,
                                sizeof(reg_rings),
                                nullptr,
                                0,
                                &len,
                                nullptr))
        {
            printf("Could not register ring buffers (%d).\n", ::GetLastError());
            ::Sleep(10000);
            RevertToSelf();
            return false;
        }
        ::Sleep(10000);
        RevertToSelf();
    }
    else
    {
        printf("Could not elevate to SYSTEM\n");
        return false;
    }



    return true;
}

int main()
{
    if (!open_tun_device())
    {
        printf("Experiment failed.\n");
    }

    printf("Size TUNRING: %d (%d)\n", sizeof(TUN_RING),  0x800000 + 0x010000 + 0x0C);
    printf("Capacity: %d\n", TUN_RING_CAPACITY(sizeof(TUN_RING)));
    if (!IS_POW2(TUN_RING_CAPACITY(sizeof(TUN_RING))))
    {
        printf("Shit gone wrong...\n");
    }

    return 0;
}

请确保运行此提升的,否则您将得到错误5 ERROR_ACCESS_DENIED

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-07-12 17:55:02

好的,经过大量的尝试和错误之后,我已经将整个设置例程从WireGuard Go代码(参见此处:https://github.com/WireGuard/wireguard-go )转换为C++,这似乎使其工作正常。它现在接受环,就像在第一根柱子上一样,这个装置被显示为连接之后.

他们正在做一些注册表调整后,安装设备(请参阅windows.go#L207 ),我认为这是蛋糕。谢谢大家帮忙找这个。

票数 1
EN

Stack Overflow用户

发布于 2020-09-15 14:00:24

对我来说,摆脱ERROR_INVALID_PARAMETER (87)的修复方法是在Visual中从x86切换到x64体系结构

票数 -1
EN

Stack Overflow用户

发布于 2020-10-16 07:18:30

这里的问题是结构的对齐。当wintun驱动程序执行8(解决方案中的/ZP8)时,您可以将结构对齐到1字节#杂注包(push,1)。这将导致不同的结构大小,因此大小检查将失败。此外,我建议您使用VirtualAlloc或映射,而不是malloc。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62670308

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档