热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开机自启动的几种方式

0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动


0x01 快速自启动目录

快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫"启动"或者"Startup"。位于该目录下的PE文件会在开机后进行自启动。由于不同版本的Windows启动目录的路径都是不同的,所以我们用一个SHGetSpecialFolderPath来获取该路径。该API位于ShlObj.dll中。我们用隐式载入方式获取。先看MSDN:

该API有四个参数。

1. HWND窗口句柄作为保留一般为NULL。

2. pszPath是输出参数。是API返回的启动目录的路径

3. csidl是一个常量,需要指明为CSIDL_STARTUP表明我们要获取自启动目录路径

4. 这是一个布尔值,指明如果目录不存在,是否要创建该目录

具体看一下csidl的其他数值参考MSDN: https://docs.microsoft.com/zh-cn/windows/desktop/shell/csidl

给出一个使用实例:

#include
#include
#include
#include
#include
#include // 该函数用于从完整路径中获取最后一个文件名,你也可以用PathStripPath函数,位于Shlwapi.dll中
LPCTSTR GetFileNameFromPath(LPCTSTR szPathName) {LPCTSTR pFind = strrchr(szPathName, '\\');if (NULL != pFind) ++pFind;return(pFind);
}// szSrcPathName指针指向源文件路径
BOOL RapidStartup(LPCTSTR szSrcPathName) {TCHAR szPathName[MAX_PATH] = { 0 };BOOL bRet = SHGetSpecialFolderPath(NULL, szPathName, CSIDL_STARTUP, TRUE);if (FALSE == bRet)return(FALSE);LPCTSTR pFileName = GetFileNameFromPath(szSrcPathName);if (!pFileName)return(FALSE);StringCchPrintf(szPathName, _countof(szPathName), "%s\\%s", szPathName, pFileName);if (!CopyFile(szSrcPathName, szPathName, FALSE))return(FALSE);return(TRUE);
}int _tmain() {if (RapidStartup("C:\\Users\\Administrator\\Desktop\\hello.exe"))printf("successful!\n");elseprintf("failed!\n");system("pause");return(0);
}



0x02 注册表自启动

注册表自启动也是一种非常常见的方式。关于注册表的详细介绍可以参见MSDN: https://docs.microsoft.com/zh-cn/windows/desktop/SysInfo/about-the-registry

这里简要介绍一下注册表。注册表是Windows操作系统中的一个重要数据库。其中包含了许多与系统相关的配置信息。Windows提供了一个编辑器方便我们编辑。可以按Win+R输入regedit来打开。或者直接去系统目录下寻找。

上面是注册表的基本布局。注册表相当复杂,这里仅仅讲关于自启动的配置的内容。设置自启动的键值项有很多,这里仅仅介绍两种通用的。其他的我也没了解感兴趣可以自己去百度。

1. HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run2. HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run

可以看到上面两项唯一的区别就是根键(简称键)不同,子键是一样的。HKEY_CURRENT_USER与HKEY_LOCAL_MACHINE的区别是影响范围。前者影响只当前用户而后者是系统配置影响所有用户。只要里面添加入新的键值对就可以实现自启动。我们具体来看下:

进行如上图的写入操作后就可以实现开机自启动。可以看到我是在HKEY_CURRENT_USER根键下也就是说这个设置只会影响我目前的登陆账户。你可以利用编辑器手动写入也可以编写程序来实现。而这里就是要讲如何编写程序实现。

想要编写程序操作注册表就必须使用系统API函数,关于注册表的API位于advapi.dll动态库中。而关于注册表的API数不胜数,具体可以MSDN查询。我们这里只使用到如下API:

RegOpenKeyEx: https://docs.microsoft.com/zh-cn/windows/desktop/api/winreg/nf-winreg-regopenkeyexa

RegCreateKeyEx: https://docs.microsoft.com/zh-cn/windows/desktop/api/winreg/nf-winreg-regcreatekeyexa

RegSetKeyValue: https://docs.microsoft.com/zh-cn/windows/desktop/api/winreg/nf-winreg-regsetkeyvaluea

RegDeleteKeyValue: https://docs.microsoft.com/zh-cn/windows/desktop/api/winreg/nf-winreg-regdeletekeyvaluea

RegCloseKey: https://docs.microsoft.com/zh-cn/windows/desktop/api/winreg/nf-winreg-regclosekey

注册表的API看上去相当繁琐,实际上大部分参数都不尽相同。这里仅给出MSDN中关于API的详细介绍,考虑到篇幅就不做累述。可以结合百度与MSDN的介绍来理解。接下去贴出代码:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#define DATA "C:\\Users\\Administrator\\Desktop\\hello.exe"
#define SUBKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
#define HKEYMACHINE HKEY_LOCAL_MACHINE
#define HKEYCURRENTUSER HKEY_CURRENT_USERBOOL RegistryStopAutoStartup(BOOL Is_HKEY_LOCAL_MACHINE, LPCTSTR pszValueName) {HKEY hKeyFirst = NULL, hKey = NULL;if (!pszValueName) {_tprintf("字符串不能为空!\n");return(FALSE);}if (Is_HKEY_LOCAL_MACHINE)hKeyFirst = HKEY_LOCAL_MACHINE;elsehKeyFirst = HKEY_CURRENT_USER;if (ERROR_SUCCESS != RegDeleteKeyValue(hKeyFirst, SUBKEY, pszValueName)) {_tprintf("%s错误代码: %d\n", "RegDeleteKeyValue", GetLastError());return(FALSE);}return(TRUE);
}BOOL RegistryAutoStartup(BOOL Is_HKEY_LOCAL_MACHINE, LPCTSTR pszKeyValue, LPCTSTR pszKeyValueData) {HKEY hKey = NULL, hKeyFirst = NULL;if (NULL == pszKeyValue || NULL == pszKeyValueData) {_tprintf("字符串不能为空!\n");return(FALSE);}if (Is_HKEY_LOCAL_MACHINE)hKeyFirst = HKEY_LOCAL_MACHINE;elsehKeyFirst = HKEY_CURRENT_USER;if (ERROR_SUCCESS != RegCreateKeyEx(hKeyFirst, SUBKEY, 0, NULL, 0, REG_OPTION_NON_VOLATILE, NULL, &hKey, NULL)) {if (0 != GetLastError())return(FALSE);else if (ERROR_SUCCESS != RegOpenKeyEx(hKeyFirst, SUBKEY, 0, KEY_ALL_ACCESS, &hKey)) {_tprintf("%s错误代码: %d\n", "RegOpenKeyEx", GetLastError());return(FALSE);}}if (ERROR_SUCCESS != RegSetKeyValue(hKeyFirst, SUBKEY, pszKeyValue, REG_SZ, pszKeyValueData, _tcslen(pszKeyValueData))) {_tprintf("%s错误代码: %d\n", "RegSetKeyValue", GetLastError());return(FALSE);}RegCloseKey(hKey);return(TRUE);
}int _tmain() {// 在注册表中写入键值RegistryAutoStartup(FALSE, "hello", DATA);// 删除注册表键值system("pause");RegistryStopAutoStartup(FALSE, "hello");system("pause");return(0);
}

注册表中还有两个值得注意的地方:

1. 操作HKEY_LOCAL_MACHINE根键内容时需要管理员权限否则会失败,而HKEY_CURRENT_USER只需要默认权限就足够了。

2. 在64位Windows下为了支持32位的程序,还存在一个WOW64层。具体参见: http://tech.163.com/06/0208/10/29ED63CH0009159F.html   这里就不再累述。我只想说的是由于32位程序的存在而为了使32位程序能够像64位程序一样使用相同方式操纵注册表而不必分开。Windows为我们设置了重定向。即假设我们为32位程序设置自启动,并且我们修改的是:

HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run

实际上会被重定位到:

HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run

即SOFTWARE下WOW6432Node中。在这个项下的内容都是用于32位程序。Windows会自动为我们设置重定向,如果不想要重定向的话可以添加KEY_WOW64_64KEY标志。




0x03 系统服务自启动

系统服务实现自启动是一种更加隐蔽的方式,但是实现起来相对复杂一点。由于系统服务是出于SESSION0,自从Vista之后系统服务就与普通应用程序隔离了。也就是说处于SESSION0中的系统服务程序不能与应用程序交互以及共享UI。类似于MessageBox或者创建对话框之类的是没有办法显示的。本质上系统服务程序是控制台程序,但是执行一些系统的操作是可以的。当然想要获取图形界面也是可以的,具体参见: https://docs.microsoft.com/zh-cn/windows/desktop/Services/interactive-services

按Win+R后输入services.msc可以打开服务窗口:

可以对服务进行启动,停止,暂停,恢复这四种操作并且可以设置手动和自动,禁止等启动方式。在一项服务上右击选择属性就能看到如下对话框:

当然,这可以选择手动操作。但这里介绍如何用Win32 API来操作。我们要使用OpenSCManager, OpenService, CreateService, StartService, DeleteService, ControlService, CloseServiceHandle来操作。具体参见MSDN:

OpenSCManager: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-openscmanagera

CreateService: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-createservicea

OpenService: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-openservicea

StartService: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-startservicea

DeleteService: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-deleteservice

ControlService: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-controlservice

CloseServiceHandle: https://docs.microsoft.com/zh-cn/windows/desktop/api/winsvc/nf-winsvc-closeservicehandle

下面贴出实例代码:

#include
#include
#include
#include // Shlwapi.dll需要在链接过程中使用导入库
#pragma comment(lib, "Shlwapi.lib")BOOL ServiceCreateOrStart(BOOL IsCreate, LPCTSTR pszServicePath) {SC_HANDLE shSCM = NULL;TCHAR szServiceName[MAX_PATH] = { 0 };SC_HANDLE shCS = NULL;if (!pszServicePath)return(FALSE);_tcscpy_s(szServiceName, _countof(szServiceName), pszServicePath);PathStripPath(szServiceName);shSCM = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);if (!shSCM) {_tprintf("OpenSCManager %d", GetLastError());return(FALSE);}if (IsCreate)shCS = CreateService(shSCM, szServiceName, szServiceName, SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START,SERVICE_ERROR_NORMAL, pszServicePath, NULL, NULL, NULL, NULL, NULL);else {shCS = OpenService(shSCM, szServiceName, SERVICE_ALL_ACCESS);if (NULL == shCS) {_tprintf("OpenService %d", GetLastError());CloseServiceHandle(shSCM);return(FALSE);}if (!StartService(shCS, 0, NULL)) {_tprintf("StartService %d", GetLastError());CloseServiceHandle(shSCM);CloseServiceHandle(shCS);return(FALSE);}}CloseServiceHandle(shSCM);CloseServiceHandle(shCS);return(TRUE);
}BOOL DelOrStopService(BOOL IsDel, LPCTSTR pszServiceName) {SC_HANDLE shSCM = NULL, shSC = NULL;SERVICE_STATUS ss = {0};TCHAR szServiceName[MAX_PATH] = {0};BOOL bRet = FALSE;if (!pszServiceName)return(FALSE);_tcscpy_s(szServiceName, _countof(szServiceName), pszServiceName);PathStripPath(szServiceName);if (NULL == (shSCM = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS))) {_tprintf("OpenSCManager: %d\n", GetLastError());return(FALSE);}if (NULL == (shSC = OpenService(shSCM, szServiceName, SERVICE_ALL_ACCESS))) {_tprintf("OpenService: %d\n", GetLastError());CloseServiceHandle(shSCM);return(FALSE);}if (IsDel)bRet = DeleteService(shSC);elsebRet = ControlService(shSC, SERVICE_CONTROL_STOP, &ss);CloseServiceHandle(shSCM);CloseServiceHandle(shSC);return(bRet);
}int _tmain() {ServiceCreateOrStart(TRUE, "C:\\Users\\Administrator\\Desktop\\SERVICEEXE.exe");DelOrStopService(TRUE, "C:\\Users\\Administrator\\Desktop\\SERVICEEXE.exe");system("pause");return(0);
}

值得注意的是操纵系统服务需要管理员权限。上面这段代码实现了系统服务的创建,启动,关闭,删除等功能。

系统服务程序的编写也和普通程序不一样。其流程类似于下面的图:

接下去我们贴出实例代码:

#include
#include //LPSERVICE_MAIN_FUNCTIONA LpserviceMainFunctiona;
TCHAR szServiceName[MAX_PATH] = "ServiceTest.exe";
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = 0;void MyFunc() {HANDLE hFile = NULL;TCHAR szText[] = "If you see this, it means service is created successfully : D";DWORD dwSize = 0;hFile = CreateFile("C:\\Users\\Administrator\\Desktop\\ttt.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);WriteFile(hFile, szText, _countof(szText), &dwSize, NULL);CloseHandle(hFile);
}BOOL SetServiceStatus(DWORD dwServiceCode) {SERVICE_STATUS ss = {0};ss.dwCurrentState = dwServiceCode;ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;ss.dwCOntrolsAccepted= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN |SERVICE_ACCEPT_PAUSE_CONTINUE;ss.dwWin32ExitCode = 0;ss.dwWaitHint = 3000;return(SetServiceStatus(g_ServiceStatusHandle, &ss));
}void __stdcall LphandlerFunction(DWORD dwControl) {switch (dwControl) {case SERVICE_CONTROL_STOP:SetServiceStatus(SERVICE_STOP_PENDING);SetServiceStatus(SERVICE_STOPPED);break;case SERVICE_CONTROL_PAUSE:SetServiceStatus(SERVICE_PAUSE_PENDING);SetServiceStatus(SERVICE_PAUSED);break;case SERVICE_CONTROL_CONTINUE:SetServiceStatus(SERVICE_CONTINUE_PENDING);SetServiceStatus(SERVICE_RUNNING);break;default:break;}
}void __stdcall LpserviceMainFunctiona(DWORD dwNumServicesArgs,LPSTR* lpServiceArgVectors
) {g_ServiceStatusHandle = RegisterServiceCtrlHandler(szServiceName, LphandlerFunction);if (0 == g_ServiceStatusHandle)return;SetServiceStatus(SERVICE_START_PENDING);SetServiceStatus(SERVICE_RUNNING);while (TRUE) {Sleep(5000);MyFunc();}
}int _tmain() {SERVICE_TABLE_ENTRY stDispatchTable[] = {{szServiceName, LpserviceMainFunctiona},{NULL, NULL}};StartServiceCtrlDispatcher(stDispatchTable);return(0);
}

这就是服务程序。注意要把想实现的功能用死循环包裹起来不然重启会导致功能无法运行。




0x04 计划任务实现自启动

(未完)

 

 

 

 

 


推荐阅读
  • Bootstrap Paginator 分页插件详解与应用
    本文深入探讨了Bootstrap Paginator这款流行的JavaScript分页插件,提供了详细的使用指南和示例代码,旨在帮助开发者更好地理解和利用该工具进行高效的数据展示。 ... [详细]
  • 本文详细探讨了在Web开发中常见的UTF-8编码问题及其解决方案,包括HTML页面、PHP脚本、MySQL数据库以及JavaScript和Flash应用中的乱码问题。 ... [详细]
  • 本文将在前几篇关于Android测试理论知识的基础上,通过ApiDemoTest实例详细探讨如何使用ApplicationTestCase进行Android应用测试。建议读者先阅读Android测试教程系列中的相关内容,以便更好地理解本文的实践部分。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • publicclassBindActionextendsActionSupport{privateStringproString;privateStringcitString; ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • Go从入门到精通系列视频之go编程语言密码学哈希算法(二) ... [详细]
  • 本文作为《WM平台上使用Sybase Anywhere 11》系列的第二篇,将继续探讨在Windows Mobile (WM) 系统中如何高效地操作Sybase Anywhere 11数据库。继上一篇关于安装与基本测试的文章之后,本篇将深入讲解数据库的具体操作方法。 ... [详细]
  • Logging all MySQL queries into the Slow Log
    MySQLoptionallylogsslowqueriesintotheSlowQueryLog–orjustSlowLog,asfriendscallit.However,Thereareseveralreasonstologallqueries.Thislistisnotexhaustive:Belowyoucanfindthevariablestochange,astheyshouldbewritteninth ... [详细]
  • 在Qt框架中,信号与槽机制是一种独特的组件间通信方式。本文探讨了这一机制相较于传统的C风格回调函数所具有的优势,并分析了其潜在的不足之处。 ... [详细]
  • 本文详细介绍了如何在循环双链表的指定位置插入新元素的方法,包括必要的步骤和代码示例。 ... [详细]
  • 使用QT构建基础串口辅助工具
    本文详细介绍了如何利用QT框架创建一个简易的串口助手应用程序,包括项目的建立、界面设计与编程实现、运行测试以及最终的应用程序打包。 ... [详细]
  • PHP面试题精选及答案解析
    本文精选了新浪PHP笔试题及最新的PHP面试题,并提供了详细的答案解析,帮助求职者更好地准备PHP相关的面试。 ... [详细]
  • 本文探讨了如何高效地计算数组中和为2的幂的偶对数量,提供了从基础到优化的方法。 ... [详细]
  • 编译原理中的语法分析方法探讨
    本文探讨了在编译原理课程中遇到的复杂文法问题,特别是当使用SLR(1)文法时遇到的多重规约与移进冲突。文章讨论了可能的解决策略,包括递归下降解析、运算符优先级解析等,并提供了相关示例。 ... [详细]
author-avatar
华东师大中北文艺部
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有