Search code examples
cwindowssocketswritefile

WriteFile with Windows Sockets returns invalid parameter error


I've been struggling with Windows Sockets for two days not being able to just use write to socket as in Linux it is. I want to write my own shellcode and I'm playing around how to redirect stdout, stdin to socket handle (that's where my playings come from). I use Windows 7 x64, build 7601 if it's necessary. Here's my code

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

This is how i run my program

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

On my second machine i just run nc to listen for this data like this :

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

I get error code 0x57 which is :

ERROR_INVALID_PARAMETER 87 (0x57) The parameter is incorrect.

Local network traffic (any data sent, pure connections handshakes and FIN)

What could be the reason of that ? I know it's not good way for sending data but MSDN says it should be possible.


Solution

  • from WriteFile documentation

    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.

    but are socket function create file (socket this is file handle, it point to FILE_OBJECT structure) with FILE_FLAG_OVERLAPPED ? this is undocumented and you cannot control this. so you need use OVERLAPPED as parameter for WriteFile.

    if use WSASocket we already here have dwFlags option and can set or not set WSA_FLAG_OVERLAPPED (which is equivalent of FILE_FLAG_OVERLAPPED for CreateFile)

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

    WriteFile call ZwWriteFile

    look for

    PLARGE_INTEGER ByteOffset [in, optional] parameter of ZwWriteFile - but it optional only if we open file as synchronous. if file opened in asynchronous i/o mode - this parameter is mandatory.

    from wrk source code

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

    this is exactly your case when you call

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

    NtWriteFile return to you STATUS_INVALID_PARAMETER which converted to win32 error ERROR_INVALID_PARAMETER

    but next code will be worked ok.

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

    because in this case ByteOffset will be point to &ov.Offset

    however for send data to socket much more better use WSASend