一、概要介绍

近期较忙,未能及时更新博客,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_ntoraddr.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); //获取IPmSocket = 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_ntoraddr.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_ACCEPTcase 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 defaultclosesocket(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.支持获取远程文件信息,实现文件目录浏览、文件下载、文件加密等。

#C++我的武器库系列#之远控核心技术实现相关推荐

  1. Java开发远控软件系列(屏幕回收)

    前言 将开发远控软件的步骤进行分布 , 然后将思路和开发步骤教给大家. 屏幕回收其实就是一直截图被控端的整个屏幕 , 然后通过网络传输显示到控制端界面上. 涉及知识点 文件流操作 Robot(机器人) ...

  2. [网络安全自学篇] 九十.远控木马详解及APT攻击中的远控和防御

    这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步.前文分享了软件来源分析,结合APT攻击中常见的判断方法,利用Python调用扩展包进 ...

  3. 糟糕!原来你的电脑就是这样被木马远控了

    作者 | 杨秀璋,责编 | 夕颜 出品 | CSDN博客 头图 | 视觉中国 这篇文章将详细讲解远控木马及APT攻击中的远控,包括木马的基本概念和分类.木马的植入方式.远控木马的通信方式.APT攻击与 ...

  4. New情报:APT28,TA505 黑产组织,VenusLocker Ransomware组织,ROKRAT远控

    周末愉快,复制粘贴链接看吧,肝系统中... 推荐一个神奇的系列,和朝鲜息息相关.. https://www.csis.org/podcasts/impossible-state 威胁情报 一. 我刚看 ...

  5. TeamViewer和向日葵远控软件的个人使用感觉

    工作中一般都用TeamViewer进行远程,向日葵有时也用,把网址和葵码告诉对方,对方安装控件,然后进行远程.个人感觉在同一网络下的TeamViewer还是比较有优势的,向日葵有时图像有点卡,显示效果 ...

  6. 晚安西南-----远控房魅影

    序言: 在这里,所有的井控设备都是自己调试,顶多来个懂行的指导下,而在家里像远控房调试与液路管线的安装只需要自己验收即可,不需要亲自安装与调试.由此,在调试远控房时,心底有些心虚.要知道它们都是直接作 ...

  7. 从零开始做远控 第五篇 屏幕监控

    如果你从没看过这系列教程请点击:从零开始做远控 简介篇 屏幕监控: 我们来到进阶课程了,我们这一节主要是讲客户端的,我们将会编写从客户端截取屏幕,然后用JEPG压缩它,最后发给服务端,形成一个动态画面 ...

  8. 远控免杀从入门到实践(6)-代码篇-Powershell

    郑重声明:文中所涉及的技术.思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!  <远控免杀从入门到实践>系列文章目录: 1.远控免杀从 ...

  9. 远控免杀从入门到实践(3)-代码篇-C/C++

    郑重声明:文中所涉及的技术.思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!  <远控免杀从入门到实践>系列文章目录: 1.远控免杀从 ...

最新文章

  1. Yii CDBCriteria常用方法
  2. qtp连接mysql 无驱动_QTP连接MySQL
  3. shiro(一)简介、理论知识
  4. 微软MS11-050漏洞的利用
  5. HDU ACM Steps攻略 ACM Steps的全部内容
  6. python定义变量名的时候、需要注意问题_python中将函数赋值给变量时需要注意的一些问题...
  7. vue工程打包上线样式错乱问题 - bug解决(4种)
  8. const,static,extern 简介
  9. Linux驱动实现灯循环闪烁,TQ2440上LED灯闪烁效果的驱动程序实现
  10. template string
  11. 拓端tecdat|Tableau 数据可视化:探索性图形分析新生儿死亡率数据
  12. 解决CAS 4.2.7 版本集群部署的各种问题
  13. 招商银行笔试题之X游戏
  14. 解决MAC上网速度慢的原因
  15. operator开发流程
  16. 【Java爬虫】爬取南通大学教务处成绩
  17. 电压源和电流的关联参考方向_在大学《电路原理》中,电流源和电压源如何判断关联参考方向和非关联参考方向?...
  18. 使用WordPress搭建个人网站
  19. 基于SpringBoot+Vue20小时打造高考志愿填报辅助系统
  20. 杭电oj刷题C语言答案+思路

热门文章

  1. 证券公司信息化3-经纪业务收入大概是个什么水平?一个普通投资者的开户过程是怎样的?
  2. 使用Navicat 连接oracle “ORA-03135: Connection Lost Contact”
  3. 5V变3.3V好用的电源芯片
  4. 一头扎进Shiro-自定义Realm
  5. JS 烧脑面试题大赏
  6. bigquant量化平台笔记
  7. 震撼,愿所有中国人,都能听到这篇演讲!
  8. Mac自动隐藏/显示程序坞有时延解决办法
  9. 基于机器学习的UEBA在账号异常检测中的应用
  10. 洛克王国服务器维护,洛克王国3月6日服务器公告 剧情更新百年大潮