WriteFile with Windows Sockets returns invalid parameter 错误

WriteFile with Windows Sockets returns invalid parameter error

我已经为 Windows 套接字苦苦挣扎了两天,无法像 Linux 那样只使用写入套接字。我想编写自己的 shellcode,并且正在研究如何将 stdout、stdin 重定向到套接字句柄(这就是我的游戏来源)。我使用 Windows 7 x64,必要时构建 7601。这是我的代码

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main (int argc,char ** argv)
{   
    // boring code starts
    if (argc < 2)
    {
        printf("Usage getstdhandle <ip> <port> ");
    }

    WSADATA wsadata;
    int result = WSAStartup (MAKEWORD(2,2),&wsadata);
    if (result != NO_ERROR)
    {
        printf("error with wsastartup");
    }

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons (atoi(argv[2]));
    server.sin_addr.s_addr = inet_addr (argv[1]);

    SOCKET soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (soc == INVALID_SOCKET)
    {
        printf("Error with creating socket");
    }

    if (connect(soc,(struct sockaddr *)&server,sizeof(server)) == SOCKET_ERROR)
    {
        printf("Problem with connecting");
    }

     // boring code ends

    const char * buf = "Tekscik \n"; // know it's not really good in new C standards
    const char buf[] = "Test\n";  // not working also, shouldn't have any influence

    bool isSent = WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10,NULL,NULL);
    DWORD ret = GetLastError();
    printf("%.08x",ret);

    closesocket(soc);
    WSACleanup();
    return 0;
}

这就是我运行我的程序

C:\Users\Domin568\Desktop>getstdhandle 192.168.56.1 5555
Tekscik
00000057     <---- Error code in hex

在我的第二台机器上,我只是 运行 nc 来监听这样的数据:

15:14|domin568[21] ~ $ nc -l -v -p 5555
Connection from 192.168.56.101:50328
15:15|domin568[22] ~ $ 

我收到错误代码 0x57,即:

ERROR_INVALID_PARAMETER 87 (0x57) The parameter is incorrect.

Local network traffic(发送的任何数据,纯连接握手和 FIN)

这可能是什么原因?我知道这不是发送数据的好方法,但 MSDN 说它应该是可能的。

MSDN 说应该可以。

是真的吗? socket handles documentation states:

A socket handle can optionally be a file handle in Windows Sockets 2. A socket handle from a Winsock provider can be used with other non-Winsock functions such as ReadFile, WriteFile, ReadFileEx, and WriteFileEx.

注意单词 "optionally"。

Per this discussion:

WriteFile with SocketHandle Fails

...

Not sure how you can read that page and think that it is a good idea to use a socket handle with ReadFile et al.

Let's start with this sentence "A socket handle can optionally be a file handle in Windows Sockets 2". That can be read two different ways:

  1. You can optionally use any socket handle as a file handle for ReadFile and friends

  2. A socket provider can optionally provide dual-use sockets that work with ReadFile as well as the socket functions.

Unfortunately there is not enough information in that article to conclusively decide whether #1 or #2 is correct. However the fact that ReadFile returns ERROR_INVALID_PARAMETER (per Mike Danes' comment) I am going to assume that #2 is the correct interpretation and your network socket is not also a file handle. (Note that frequently the MSDN documentation is written more from the perspective of the team that implemented API than from a consumer of the API. If you look at it in that light, #2 is the more likely interpretation -- I will agree that it is annoying because a consumer of the API is more likely to understand the sentence as #1)

来自 WriteFile 文档

lpOverlapped [in, out, optional]

A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise this parameter can be NULL.

但是是socket函数创建文件(套接字这是文件句柄,它指向FILE_OBJECT 结构 ) 和 FILE_FLAG_OVERLAPPED ?这是未记录的,您无法控制。所以你需要使用 OVERLAPPED 作为 WriteFile.

的参数

if use WSASocket 我们这里已经有 dwFlags 选项并且可以设置或不设置 WSA_FLAG_OVERLAPPED (这相当于 FILE_FLAG_OVERLAPPED for CreateFile)

为什么 OVERLAPPED structure is required when we use hFile opened with FILE_FLAG_OVERLAPPED flag (no FO_SYNCHRONOUS_IO flag in FILE_OBJECT) ?

WriteFile 调用 ZwWriteFile

寻找

PLARGE_INTEGER ByteOffset [in, optional] ZwWriteFile 的参数 - 但仅当我们以同步方式打开文件时才可选。如果文件以异步 i/o 模式打开 - 此参数是 强制性

来自 wrk 源代码

if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
}
else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {

        //
        // The file is not open for synchronous I/O operations, but the
        // caller did not specify a ByteOffset parameter.  This is an error
        // situation, so cleanup and return with the appropriate status.
        //

        if (eventObject) {
            ObDereferenceObject( eventObject );
        }
        ObDereferenceObject( fileObject );
        return STATUS_INVALID_PARAMETER;

    }

这正是你打电话时的情况

WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10,NULL,NULL);

NtWriteFile return 给你STATUS_INVALID_PARAMETER 里面转换成win32报错ERROR_INVALID_PARAMETER

但下一个代码将正常工作。

OVERLAPPED ov = {};
BOOL isSent = WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10, 0, &ov);

因为在这种情况下 ByteOffset 将指向 &ov.Offset

然而,为了将数据发送到套接字,更好地使用 WSASend