#C++我的武器庫系列#之遠控核心技術實現

一、概要介紹      

        近期較忙,未能及時更新博客,Python告一段落後,開始基於C++的武器庫核心技術實現,本期基於C++MFC,利用socket,通過非阻塞的方式實現client與server端的通信,通過client向server發起指令獲取相關信息。

     服務器端函數邏輯: socket()->bind()->accept()->send()/recv()->closesocket();

     客戶端函數邏輯:socket()->connet()->send()/recv()->closesocket();

二、系統核心代碼-服務端


// UMDlg.cpp : 實現文件
//

#include "stdafx.h"
#include "UM.h"
#include "UMDlg.h"
#include "afxdialogex.h"



#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用於應用程序“關於”菜單項的 CAboutDlg 對話框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();


// 對話框數據
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 實現
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
	
END_MESSAGE_MAP()


// CUMDlg 對話框




CUMDlg::CUMDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CUMDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CUMDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CUMDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_MESSAGE(UM_SERVER, OnSock)
	ON_WM_CLOSE()
END_MESSAGE_MAP()


// CUMDlg 消息處理程序

BOOL CUMDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 將“關於...”菜單項添加到系統菜單中。

	// IDM_ABOUTBOX 必須在系統命令範圍內。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
	//  執行此操作
	SetIcon(m_hIcon, TRUE);			// 設置大圖標
	SetIcon(m_hIcon, FALSE);		// 設置小圖標

	// TODO: 在此添加額外的初始化代碼

	//----------------------------初始化-------------------------
	//WSDATA wsaData;
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2),&wsaData);//初始化
	listenSocket =  socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //創建套接字;SOCK_STREAM:流套接字 SOCK_DGRAM:數據包套接字;SOCK_RAM:原始協議套接字;TCP形式
	WSAAsyncSelect(listenSocket,GetSafeHwnd(),UM_SERVER,FD_ACCEPT); //非阻塞模式 1:接收消息窗口;2:消息;3:通知碼;
	//對socket_in結構體進行填充。包括地址、端口等信息
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.S_un.S_addr =ADDR_ANY; //inet_addr("192.168.1.102");  //將點分10進制IP,轉換成無符號long類型  也可以設置ADDR_ANY; 逆函數 inet_ntor
	addr.sin_port = htons(5555);//主機字節轉換成網絡字節,在端口方面,x86爲小尾方式  TCP/IP爲大尾方式,所以需要轉換。大尾與小尾區別爲字節存儲順序相反
	bind(listenSocket,(SOCKADDR *)&addr,sizeof(addr)); //綁定IP地址和端口,並處於監聽狀態
	listen(listenSocket,1);

	return TRUE;  // 除非將焦點設置到控件,否則返回 TRUE
}
//處理通知碼
LRESULT CUMDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
	if(WSAGETSELECTERROR(lParam)){
	  return 1;
	}
	switch(WSAGETSELECTEVENT(lParam)){
		
	case FD_ACCEPT:
		{
			sockaddr_in clientAddr;
			int nSize = sizeof(clientAddr);
			clientSocket = accept(listenSocket,(SOCKADDR *)&clientAddr,&nSize); //建立
			WSAAsyncSelect(clientSocket,GetSafeHwnd(),UM_SERVER,FD_READ|FD_CLOSE); //非阻塞模式 1:接收消息窗口;2:消息;3:通知碼;
			strMsg.Format("請求的地址是%s:%d",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
			DATA_MSG dataMsg;
			dataMsg.bType = TEXTMSG;
			dataMsg.bClass = 0;
			lstrcpy(dataMsg.szValue,HELPMSG);
			send(clientSocket,(const char *)&dataMsg,sizeof(dataMsg),0); //發送
			break;
		}
	case FD_READ:
		{
			char szBuf[MAXBYTE] = {0};
			recv(clientSocket,szBuf,MAXBYTE,0); //接收
			DispatchMsg(szBuf);
			strMsg = "對方發來指令";
			strMsg += szBuf;
			break;
		}
	case FD_CLOSE:
		{
			closesocket(clientSocket);
			strMsg = "對方關閉連接";
			break;
		}
	}
	InsertMsg();
	return 1;
}

//匹配對應的操作命令
void CUMDlg::DispatchMsg(char* szBuf)
{
	DATA_MSG  dataMsg;
	ZeroMemory((void *)&dataMsg,sizeof(dataMsg)); 
	if(!strcmp(szBuf,"help")){ 
		dataMsg.bType = TEXTMSG;
		dataMsg.bClass = 0;
		lstrcpy(dataMsg.szValue,HELPMSG);
	}
	else if(!strcmp(szBuf,"getsysinfo")){
	    SYS_INFO SysInfo;
        GetSysInfo(&SysInfo);
        dataMsg.bType = BINARYMSG;
        dataMsg.bClass = SYSINFO;
		SysInfo.szComputerName;
		CString cName= SysInfo.szComputerName;
		CString uName= SysInfo.szUserName;
		  
		lstrcpy(dataMsg.szValue,"主機名:"+cName+"  用戶:"+uName);
		//memcpy((void *)dataMsg.szValue, &SysInfo.szUserName, sizeof(dataMsg));
		//memcpy((void *)dataMsg.szValue,(char *) &SysInfo,sizeof(dataMsg));

	}
	send(clientSocket,(const char *)&dataMsg,sizeof(dataMsg),0); //發送
}

//獲取系統信息
void  CUMDlg::GetSysInfo(PSYS_INFO SysInfo)
{
	unsigned long nSize = 0;
    SysInfo->OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&SysInfo->OsVer);
    nSize = NAME_LEN;
    GetComputerName(SysInfo->szComputerName, &nSize);
    nSize = NAME_LEN;
    GetUserName(SysInfo->szUserName, &nSize);
	//MessageBox(SysInfo->szUserName);
}


//輸出信息
void CUMDlg::InsertMsg()
{
    CString strMsgNew;
    GetDlgItemText(IDC_EDIT1, strMsgNew);//獲取內容
    strMsg += "\r\n";
    strMsg += "----------------------------------------\r\n";
    strMsg += strMsgNew;
    SetDlgItemText(IDC_EDIT1, strMsg); //填充內容
    strMsg = "";
}
void CUMDlg::OnClose() 
{
	// TODO: Add your message handler code here and/or call default
    // 關閉監聽套接字,並釋放Winsock庫
    closesocket(clientSocket);
    closesocket(listenSocket);
    WSACleanup();
	CDialogEx::OnClose();
}

void CUMDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向對話框添加最小化按鈕,則需要下面的代碼
//  來繪製該圖標。對於使用文檔/視圖模型的 MFC 應用程序,
//  這將由框架自動完成。

void CUMDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用於繪製的設備上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使圖標在工作區矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 繪製圖標
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR CUMDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CUMDlg::OnEnChangeEdit1()
{
	// TODO:  如果該控件是 RICHEDIT 控件,它將不
	// 發送此通知,除非重寫 CDialogEx::OnInitDialog()
	// 函數並調用 CRichEditCtrl().SetEventMask(),
	// 同時將 ENM_CHANGE 標誌“或”運算到掩碼中。

	// TODO:  在此添加控件通知處理程序代碼
}

三、系統核心代碼-客戶端


// UMCLIENTDlg.cpp : 實現文件
//

#include "stdafx.h"
#include "UMCLIENT.h"
#include "UMCLIENTDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用於應用程序“關於”菜單項的 CAboutDlg 對話框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 對話框數據
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 實現
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CUMCLIENTDlg 對話框




CUMCLIENTDlg::CUMCLIENTDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CUMCLIENTDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CUMCLIENTDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CUMCLIENTDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CUMCLIENTDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CUMCLIENTDlg::OnBnClickedButton2)
	ON_MESSAGE(UM_CLIENT, OnSock)
END_MESSAGE_MAP()


// CUMCLIENTDlg 消息處理程序

BOOL CUMCLIENTDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 將“關於...”菜單項添加到系統菜單中。

	// IDM_ABOUTBOX 必須在系統命令範圍內。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
	//  執行此操作
	SetIcon(m_hIcon, TRUE);			// 設置大圖標
	SetIcon(m_hIcon, FALSE);		// 設置小圖標

	// TODO: 在此添加額外的初始化代碼
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
	return TRUE;  // 除非將焦點設置到控件,否則返回 TRUE
}

void CUMCLIENTDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向對話框添加最小化按鈕,則需要下面的代碼
//  來繪製該圖標。對於使用文檔/視圖模型的 MFC 應用程序,
//  這將由框架自動完成。

void CUMCLIENTDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用於繪製的設備上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使圖標在工作區矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 繪製圖標
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR CUMCLIENTDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


//連接
void CUMCLIENTDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知處理程序代碼
	char szBtnName[10] = {0};
	GetDlgItemText(IDC_BUTTON1,szBtnName,10);
	if(!lstrcmp(szBtnName,"斷開連接")){
		SetDlgItemText(IDC_BUTTON1,"連接");
		(GetDlgItem(IDC_EDIT2)->EnableWindow(FALSE)); //內容區域
		(GetDlgItem(IDC_EDIT4)->EnableWindow(FALSE)); //命令區域
		(GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE)); //發送按鈕
		closesocket(mSocket);
		strMsg = "主動斷開連接";
		InsertMsg();
		return;
	}
	char szIpAddr[MAXBYTE] = {0};
	GetDlgItemText(IDC_EDIT1,szIpAddr,MAXBYTE); //獲取IP
	mSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //創建套接字;SOCK_STREAM:流套接字 SOCK_DGRAM:數據包套接字;SOCK_RAM:原始協議套接字;TCP形式
	WSAAsyncSelect(mSocket,GetSafeHwnd(),UM_CLIENT,FD_READ|FD_CONNECT|FD_CLOSE); //非阻塞模式 1:接收消息窗口;2:消息;3:通知碼;
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.S_un.S_addr = inet_addr(szIpAddr);  //將點分10進制IP,轉換成無符號long類型  也可以設置ADDR_ANY; 逆函數 inet_ntor
	addr.sin_port = htons(5555);//主機字節轉換成網絡字節,在端口方面,x86爲小尾方式  TCP/IP爲大尾方式,所以需要轉換。大尾與小尾區別爲字節存儲順序相反
	connect(mSocket,(SOCKADDR *)&addr,sizeof(addr)); //連接
}

//發送命令
void CUMCLIENTDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知處理程序代碼
	char szBuf[MAXBYTE] = {0};
	GetDlgItemText(IDC_EDIT4,szBuf,MAXBYTE); //獲取命令
	send(mSocket,szBuf,MAXBYTE,0); //發送命令
}

//響應通知碼
LRESULT CUMCLIENTDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
	if(WSAGETSELECTERROR(lParam)){
	  return 1;
	}
	switch(WSAGETSELECTEVENT(lParam)){
	
	//處理 FD_ACCEPT
	case FD_CONNECT:
		{
			(GetDlgItem(IDC_EDIT2)->EnableWindow(TRUE)); //內容區域
			(GetDlgItem(IDC_EDIT4)->EnableWindow(TRUE)); //命令區域
			(GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE)); //發送按鈕
			SetDlgItemText(IDC_BUTTON1,"斷開連接");
			strMsg = "連接成功";
			break;
		}
	case FD_READ:
		{
			DATA_MSG dataMsg;
			recv(mSocket,(char *) &dataMsg,sizeof(dataMsg),0); //接收
			DispatchMsg((char *)&dataMsg);
			break;
		}
	case FD_CLOSE:
		{
			(GetDlgItem(IDC_EDIT2)->EnableWindow(FALSE)); //內容區域
			(GetDlgItem(IDC_EDIT4)->EnableWindow(FALSE)); //命令區域
			(GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE)); //發送按鈕
			closesocket(mSocket);
			strMsg = "對方斷開連接";
			break;
		}
	}
	InsertMsg();//輸出到前臺
	return 1;
}

//匹配消息
void CUMCLIENTDlg::DispatchMsg(char* szBuf)
{
	DATA_MSG DataMsg;
	memcpy((void*)&DataMsg, (const void *)szBuf, sizeof(DATA_MSG));
	if(DataMsg.bType = TEXTMSG){ //幫助信息
		strMsg = DataMsg.szValue;
	}
	else {
		if(DataMsg.bClass == SYSINFO){ //系統信息
			ParseSysInfo((PSYS_INFO )&DataMsg.szValue);
		}
	}
}



//解析系統信息
void CUMCLIENTDlg::ParseSysInfo(PSYS_INFO sysInfo)
{
	if ( sysInfo->OsVer.dwPlatformId == VER_PLATFORM_WIN32_NT )
    {
        if ( sysInfo->OsVer.dwMajorVersion == 5 && sysInfo->OsVer.dwMinorVersion == 1 )
        {
            strMsg.Format("對方系統信息:\r\n\t Windows %s", sysInfo->OsVer.szCSDVersion);
        }
        else if ( sysInfo->OsVer.dwMajorVersion == 5 && sysInfo->OsVer.dwMinorVersion == 0)
        {
            strMsg.Format("對方系統信息:\r\n\t Windows 2K");
        }
    }
    else
    {
        strMsg.Format("對方系統信息:\r\n\t Other System \r\n");
    }
    
    strMsg += "\r\n";
    strMsg += "\t Computer Name is ";
    strMsg += sysInfo->szComputerName;
    strMsg += "\r\n";
    strMsg += "\t User Name is ";
    strMsg += sysInfo->szUserName;
}

void CUMCLIENTDlg::OnClose() 
{
	// TODO: Add your message handler code here and/or call default
    closesocket(mSocket);
    WSACleanup();
	
	CUMCLIENTDlg::OnClose();
}

//輸出信息
void CUMCLIENTDlg::InsertMsg()
{
    CString strMsgNew;
    GetDlgItemText(IDC_EDIT2, strMsgNew);//獲取內容
    strMsg += "\r\n";
    strMsg += "----------------------------------------\r\n";
    strMsg += strMsgNew;
    SetDlgItemText(IDC_EDIT2, strMsg); //填充內容
    strMsg = "";
}

       需要注意的是,在X86架構下,數值存儲方式默認是小尾方式字節順序(內存高位地址存放高位字節數據),TCP/IP數值存儲方式默認是大尾方式字節順序(內存高位地址存放低位字節數據)。

四、後期優化

在深度層面:1.利用系統漏洞或者U盤病毒進行傳播,以反彈方式與client進行交互。2.掃描端口,進行端口複用。

在廣度層面:1.支持執行CMD命令;1.支持獲取遠程文件信息,實現文件目錄瀏覽、文件下載、文件加密等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章