都知道普通的方法:windows键+R键,输入命令“mstsc”确认打开远程桌面连接窗口,输入需要远程的计算机控制的IP地址用户名和密码,登录远程云电脑控制。非常麻烦。直接上代码:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#pragma comment(lib, "wsock32")
#pragma comment(lib,"crypt32.lib")//加密库文件
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )//隐藏黑窗口
std::string myLogPath;
void WriteLog(std::string msg);
/**********************************************
函数名:split
功能:字符串分割
参数1:字符串
参数2:分隔符
返回值:vector容器
**********************************************/
std::vector split(std::string str, std::string separator)
{
std::vector result;
int cutAt;
while ((cutAt = str.find(separator)) != str.npos)
{
if (cutAt > 0)
{
result.push_back(str.substr(0, cutAt));
}
str = str.substr(cutAt + separator.size());
}
if (str.length() > 0)
{
result.push_back(str);
}
return result;
}
/**********************************************
函数名:AsciiToUnicode
功能:Ascii转Unicode
参数1:Ascii字符串
返回值:Unicode
**********************************************/
std::wstring AsciiToUnicode(const std::string& str) {
// 预算-缓冲区中宽字节的长度
int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
// 给指向缓冲区的指针变量分配内存
wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
// 开始向缓冲区转换字节
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
std::wstring ret_str = pUnicode;
free(pUnicode);
return ret_str;
}
/**********************************************
函数名:DeleteRegeditKey
功能:遍历删除注册表项
参数1:根项名称
参数2:注册表项名
**********************************************/
VOID DeleteRegeditKey(HKEY rootKey, LPCSTR subKey)
{
HKEY hKey;
if (RegOpenKeyExA(rootKey, subKey, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
{
while (true)
{
// 注册表项名称最长为251个有效字符
char subKeyName[251] = "";
if (RegEnumKeyA(hKey, 0, subKeyName, 251) != ERROR_SUCCESS)
break;
// 这里的2是路径分隔符"\"和结束符的占位
size_t fullPathLen = strlen(subKey) + 2 + strlen(subKeyName);
char *fullPath = new char[fullPathLen];
strcpy(fullPath, subKey);
strcat(fullPath, "\\");
strcat(fullPath, subKeyName);
DeleteRegeditKey(rootKey, fullPath);
delete[] fullPath;
}
RegDeleteKeyA(rootKey, subKey);
RegCloseKey(hKey);
}
}
/**********************************************
函数名:ControlRegedit
功能:操作注册表
参数1:bat脚本文件名
参数2:新增注册项名(前端调用名称)
参数3:安装(TRUE)或卸载(FALSE)注册表
返回值:成功返回TRUE
**********************************************/
BOOL WriteRegedit(std::string ExeFileName="", std::string RegeditName="qtc",BOOL InstallRegedit = TRUE)
{
HKEY hKey = NULL;
DWORD dwDisposition;
//获取文件名
char szModuleFileName[MAX_PATH];
GetModuleFileNameA(NULL,szModuleFileName,MAX_PATH);
//获取运行文件目录
char FilePath[MAX_PATH];
GetCurrentDirectoryA(MAX_PATH, FilePath);
//判断是否卸载注册表
if(FALSE == InstallRegedit)
{
//删除注册表代码
DeleteRegeditKey(HKEY_CLASSES_ROOT,RegeditName.c_str());
return TRUE;
}
//创建或者打开qtc
if(ERROR_SUCCESS == RegCreateKeyExA(HKEY_CLASSES_ROOT, RegeditName.c_str(), 0, NULL,REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition))
{
//写入默认"qtcProtocol"和URLProtocol=""
if (ERROR_SUCCESS != RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)(RegeditName+"Protocol").c_str(), (RegeditName+"Protocol").size()) ||
ERROR_SUCCESS != RegSetValueExA(hKey, "URL Protocol", 0, REG_SZ, (BYTE*)"", strlen("")))
{
return FALSE;
}
RegCloseKey(hKey);
}
//创建或者打开qtc\DefaultIcon
if(ERROR_SUCCESS == RegCreateKeyExA(HKEY_CLASSES_ROOT, (RegeditName+"\\DefaultIcon").c_str(), 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition))
{
char strPath[MAX_PATH]={};
if(ExeFileName.empty()){
sprintf(strPath,"%s,%d",szModuleFileName,1);
}else{
sprintf(strPath,"%s\\%s,%d",FilePath,ExeFileName.c_str(),1);
}
//写入默认值"目录\open.bat,1"
if (ERROR_SUCCESS != RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)strPath, strlen(strPath)))
{
return FALSE;
}
RegCloseKey(hKey);
}
//创建或者打开qtc\\shell\\open\\command
if(ERROR_SUCCESS == RegCreateKeyExA(HKEY_CLASSES_ROOT, (RegeditName+"\\shell\\open\\command").c_str(), 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition))
{
char strPath1[MAX_PATH]={};
if(ExeFileName.empty()){
sprintf(strPath1,"\"%s\" \"%%1\"",szModuleFileName);
}else{
sprintf(strPath1,"\"%s\\%s\" \"%%1\"",FilePath, ExeFileName.c_str());
}
//写入默认值"\"目录\open.bat\" \"%1\""
if (ERROR_SUCCESS != RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)strPath1, strlen(strPath1)))
{
return FALSE;
}
RegCloseKey(hKey);
}
return TRUE;
}
/**********************************************
函数名:EncryptionPassword
功能:加密
参数1:传入的字符串参数
参数2:传入加密后的字符串引用
返回值:BOOL
**********************************************/
BOOL EncryptionPassword(const std::wstring str, std::string &cipherText)
{
cipherText.clear();
if(str.empty())
return FALSE;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
//mstsc.exe中使用的是unicode,所以必须做宽字符转换
BYTE *pbDataInput =(BYTE *)str.c_str();
DWORD cbDataInput = wcslen(str.c_str())*sizeof(wchar_t);
DataIn.pbData = pbDataInput;
DataIn.cbData = cbDataInput;
if(CryptProtectData(&DataIn, str.c_str(), NULL, NULL, NULL, 0, &DataOut))
{
printf("The encryption phase worked.\n");
int count=0;
char tempStr[10]={};
while ( count <= (int)DataOut.cbData ){
// 因为一个unsigned int 占32位
// 转换成成16进制要占两位
// 所以这里需要用%02
sprintf(tempStr,"%02X",DataOut.pbData[count]);
cipherText += tempStr;
//printf("%02X",DataOut.pbData[count]);
count++;
}
}
else
{
return FALSE;
}
return TRUE;
}
BOOL EncryptionPasswordA(const std::string str, std::string &cipherText)
{
std::wstring _str = AsciiToUnicode(str);
return EncryptionPassword(_str,cipherText);
}
/**********************************************
函数名:WriteRDPFile
功能:功能:写入RDP文件
参数1:RDP文件路径
参数2:解析好的前端数据
参数3:色彩深度
返回值:BOOL
**********************************************/
BOOL WriteRDPFile(std::string RDPFilePath,const std::vector &info, std::string colordepth="32")
{
FILE *fp;
if((fp=fopen(RDPFilePath.c_str(),"wb"))==NULL)
{
return FALSE;
}
std::string tempStr;
fputs("screen mode id:i:2\n",fp);
fputs("smart sizing:i:1\n",fp);
fputs("use multimon:i:0\n",fp);
//动态修改屏幕分辨率
int nScreenWidth, nScreenHeight;
nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
char strScreen[128]={};
sprintf(strScreen,"desktopwidth:i:%d\n",nScreenWidth);
fputs(strScreen,fp);
memset(strScreen,0,sizeof(strScreen));
sprintf(strScreen,"desktopheight:i:%d\n",nScreenHeight);
fputs(strScreen,fp);
fputs("session bpp:i:32\n",fp);
fputs("winposstr:s:0,1,73,77,873,654\n",fp);
fputs("compression:i:1\n",fp);
fputs("keyboardhook:i:2\n",fp);
fputs("audiocapturemode:i:0\n",fp);
fputs("videoplaybackmode:i:1\n",fp);
fputs("connection type:i:7\n",fp);
fputs("networkautodetect:i:1\n",fp);
fputs("bandwidthautodetect:i:1\n",fp);
fputs("displayconnectionbar:i:1\n",fp);
fputs("enableworkspacereconnect:i:0\n",fp);
fputs("disable wallpaper:i:0\n",fp);
fputs("allow font smoothing:i:0\n",fp);
fputs("allow desktop composition:i:0\n",fp);
fputs("disable full window drag:i:1\n",fp);
fputs("disable menu anims:i:1\n",fp);
fputs("disable themes:i:0\n",fp);
fputs("disable cursor setting:i:0\n",fp);
fputs("bitmapcachepersistenable:i:1\n",fp);
//写入ip信息
if(info.size() > 0){
tempStr = "full address:s:"+info[0];
//写入端口信息
if(info.size() > 1){
tempStr += ":";
tempStr+=info[1];
}
tempStr+="\n";
}
else{
tempStr = "full address:s:\n";
}
fputs(tempStr.c_str(),fp);
fputs("audiomode:i:0\n",fp);
fputs("redirectprinters:i:1\n",fp);
fputs("redirectcomports:i:0\n",fp);
fputs("redirectsmartcards:i:1\n",fp);
fputs("redirectclipboard:i:1\n",fp);
fputs("redirectposdevices:i:0\n",fp);
fputs("autoreconnection enabled:i:1\n",fp);
fputs("authentication level:i:2\n",fp);//注意:身份验证级别
fputs("prompt for credentials:i:0\n",fp);
fputs("negotiate security layer:i:1\n",fp);
fputs("remoteapplicationmode:i:0\n",fp);
fputs("alternate shell:s:\n",fp);
fputs("shell working directory:s:\n",fp);
fputs("gatewayhostname:s:\n",fp);
fputs("gatewayusagemethod:i:4\n",fp);
fputs("gatewaycredentialssource:i:4\n",fp);
fputs("gatewayprofileusagemethod:i:0\n",fp);
fputs("promptcredentialonce:i:0\n",fp);
fputs("gatewaybrokeringtype:i:0\n",fp);
fputs("use redirection server name:i:0\n",fp);
fputs("rdgiskdcproxy:i:0\n",fp);
fputs("kdcproxyname:s:\n",fp);
fputs("drivestoredirect:s:\n",fp);
//写入用户名和密码
if(info.size() > 2)
{
tempStr = "username:s:" +info[2]+"\n";
fputs(tempStr.c_str(),fp);
}
if(info.size() > 3)
{
std::string str;
//密码加密
if(TRUE == EncryptionPasswordA(info[3],str))
{
tempStr = "password 51:b:" +str+"\n";
fputs(tempStr.c_str(),fp);
}
}
fputs("enablecredsspsupport:i:0\n",fp);//注意:当存在此行时,您不必在建立远程桌面连接之前提供凭据
fclose(fp);
WriteLog("rdp文件更新成功");
return TRUE;
}
/**********************************************
函数名:StartUpMSTSCLogin
功能:启动远程连接且自动登录
参数1:RDP文件路径
参数2:解析好的前端数据
**********************************************/
VOID StartUpMSTSCLogin(std::string RDPFilePath,const std::vector &info)
{
char tempStr[MAX_PATH]={};
//启动rdp
memset(tempStr,0,sizeof(tempStr));
sprintf(tempStr,"mstsc \"%s\" /console /v: ",RDPFilePath.c_str());
if(info.size() > 0){
strcat(tempStr,info[0].c_str());
strcat(tempStr,":");
}
if(info.size() > 1){
strcat(tempStr,info[1].c_str());
}
WriteLog("启动rdp服务");
//system(tempStr);
WinExec(tempStr,SW_HIDE);
}
/**********************************************
函数名:AnalyticInfo
功能:解析参数(ip,port,username,pwd,userid,time)
参数1:个数
参数2:二级指针
参数3:检测头
返回值:vector容器
**********************************************/
std::vector AnalyticInfo(int argc, char *argv[], std::string KeyWord = "qtc://")
{
std::vector vec;
//1.找到前端传过来的数据 获取关键字“qtc://"
for(int i = 0; i< argc;++i)
{
if(strstr(argv[i],KeyWord.c_str()) && strstr(argv[i],"ip="))
{
//2.提取重要信息(ip,port,username,pwd,userid,time)
//格式:qtc://ip=10.10.1.1&port=22&uname=Administrator&pwd=AiTest&userid=?&time=?
std::string webinfo = argv[i];
if(webinfo[webinfo.size()-1] == '/')
{
webinfo.erase(webinfo.end() - 1);
}
auto vec1 = split(webinfo,"&");
for(int i = 0;i < vec1.size(); ++i)
{
auto vec2 = split(vec1[i],"=");
if(vec2.size()>1){
vec.push_back(vec2[1]);
}
else{
vec.push_back("");
}
vec2.clear();
}
vec1.clear();
/*char tempStr[6][128]={};
sscanf(argv[i],(KeyWord+"ip=%[^&]&port=%[^&]&uname=%[^&]&pwd=%[^&]&userid=%[^&]&time=%[^/]").c_str(),
tempStr[0],tempStr[1],tempStr[2],tempStr[3],tempStr[4],tempStr[5]);
for(int j = 0; j<6;++j)
{
vec.push_back(tempStr[j]);
}//这种方法遇见空字符串,sscanf就会返回*/
return vec;
}
}
WriteLog("前端无数据传过来");
return vec;
}
/*写入日志*/
void WriteLog(std::string msg)
{
//获取本地时间
time_t timep;
time (&timep);
char tmp[128]={},logName[56]={};
strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S",localtime(&timep) );
FILE *fp;
if((fp=fopen(myLogPath.c_str(),"a+"))==NULL)
{
return;
}
time_t now_time=time(NULL);
std::string strLog = tmp;
strLog = strLog + " " + msg + "\n";
fputs(strLog.c_str(),fp);
fclose(fp);
}
int main(int argc,char *argv[],char *envp[]){
WriteLog("运行远程桌面插件");
//0.分解运行程序路径
char drive[_MAX_DRIVE] = {0};
char dir[_MAX_DIR] = {0};
char fname[_MAX_FNAME] = {0};
char ext[_MAX_EXT] = {0};
_splitpath( argv[0], drive, dir, fname, ext );
//组建log日志路径
time_t timep;
time (&timep);
char logName[56]={};
strftime(logName, sizeof(logName), "%Y-%m-%d",localtime(&timep) );
myLogPath = drive;
myLogPath = myLogPath + dir + logName + ".log";
//1.提取前端信息
std::vector tempVec = AnalyticInfo(argc,argv);
//3.定义rdp文件路径
char rdpPath[MAX_PATH]={};
strcpy(rdpPath,drive);
strcat(rdpPath,dir);
strcat(rdpPath,"rmstsc.rdp");
//4.写入RDP文件
WriteRDPFile(rdpPath,tempVec);
//5.写入注册表信息
WriteRegedit();
//6.启动远程桌面自动登录
StartUpMSTSCLogin(rdpPath,tempVec);
for(int i = 0;i < tempVec.size();++i)
{
char strInfo[64]={};
sprintf(strInfo,"前端参数%d 传入",i+1);
tempVec[i]==""?strcat(strInfo,"null"):strcat(strInfo,"成功");
WriteLog(strInfo);
}
//6.释放容器
tempVec.clear();
//system("pause");
return 0;
}
这里我附上调用方法:
在浏览输入网址:
qtc://ip=10.10.1.1&port=22&uname=Administrator&pwd=AiTest&userid=?&time=?
其中qtc是名称,其中qtc://之后就是传入的参数