安全开发专题
1、自启动
1、课程目标
- 理解Windows系统自启动机制
- 掌握常见的自启动技术实现
- 实现多种自启动方法
- 了解自启动的检测和防护
2、名词解释
| 术语 | 全称 | 解释 |
|---|---|---|
| Auto-run | 自动运行 | 系统启动时自动执行程序 |
| Registry | 注册表 | Windows系统配置数据库 |
| Startup Folder | 启动文件夹 | 用户登录时自动执行的程序目录 |
| Service | 服务 | 系统后台运行的程序 |
| Persistence | 持久化 | 保持程序持续运行的能力 |
3、技术原理
1. Windows自启动机制
用户级自启动:
HKCU\Software\Microsoft\Windows\CurrentVersion\Run
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
系统级自启动:
HKLM\Software\Microsoft\Windows\CurrentVersion\Run
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\SYSTEM\CurrentControlSet\Services
其他自启动位置:
HKCU\Environment\UserInitMprLogonScript
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell
Scheduled Tasks
2. 自启动检测点
// 常见检测注册表项
const char* autorunKeys[] = {
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServices",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce",
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell",
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Userinit"
};
3、代码实现
1. 注册表自启动
// registry_autorun.cpp
// 注册表自启动实现
#include <windows.h>
#include <stdio.h>
#include <string>
// 添加注册表自启动项
bool AddRegistryAutorun(const char* appName, const char* appPath, bool systemWide = false) {
HKEY hKey;
const char* regPath = systemWide ?
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" :
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
LONG result = RegOpenKeyExA(
systemWide ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
regPath,
0,
KEY_SET_VALUE,
&hKey
);
if (result != ERROR_SUCCESS) {
printf("[-] Failed to open registry key: %ld\n", result);
return false;
}
result = RegSetValueExA(
hKey,
appName,
0,
REG_SZ,
(const BYTE*)appPath,
(DWORD)strlen(appPath) + 1
);
RegCloseKey(hKey);
if (result == ERROR_SUCCESS) {
printf("[+] Added registry autorun: %s\n", appName);
return true;
} else {
printf("[-] Failed to set registry value: %ld\n", result);
return false;
}
}
// 删除注册表自启动项
bool RemoveRegistryAutorun(const char* appName, bool systemWide = false) {
HKEY hKey;
const char* regPath = systemWide ?
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" :
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
LONG result = RegOpenKeyExA(
systemWide ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
regPath,
0,
KEY_SET_VALUE,
&hKey
);
if (result != ERROR_SUCCESS) {
return false;
}
result = RegDeleteValueA(hKey, appName);
RegCloseKey(hKey);
if (result == ERROR_SUCCESS) {
printf("[+] Removed registry autorun: %s\n", appName);
return true;
}
return false;
}
// 查询注册表自启动项
void ListRegistryAutorun(bool systemWide = false) {
HKEY hKey;
const char* regPath = systemWide ?
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" :
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
LONG result = RegOpenKeyExA(
systemWide ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
regPath,
0,
KEY_READ,
&hKey
);
if (result != ERROR_SUCCESS) {
return;
}
printf("\n[%s] Registry Autorun Entries:\n", systemWide ? "System" : "User");
printf("----------------------------------------\n");
DWORD index = 0;
char name[256];
DWORD nameSize;
BYTE value[1024];
DWORD valueSize;
DWORD valueType;
while (true) {
nameSize = sizeof(name);
valueSize = sizeof(value);
result = RegEnumValueA(
hKey,
index,
name,
&nameSize,
NULL,
&valueType,
value,
&valueSize
);
if (result == ERROR_NO_MORE_ITEMS) {
break;
}
if (result == ERROR_SUCCESS) {
printf("%-20s: %s\n", name, (char*)value);
}
index++;
}
RegCloseKey(hKey);
}
2. 启动文件夹自启动
// startup_folder.cpp
// 启动文件夹自启动实现
#include <windows.h>
#include <shlobj.h>
#include <stdio.h>
#include <string>
// 获取启动文件夹路径
std::string GetStartupFolderPath(bool allUsers = false) {
char path[MAX_PATH];
if (allUsers) {
// 所有用户启动文件夹
if (SHGetSpecialFolderPathA(NULL, path, CSIDL_COMMON_STARTUP, FALSE)) {
return std::string(path);
}
} else {
// 当前用户启动文件夹
if (SHGetSpecialFolderPathA(NULL, path, CSIDL_STARTUP, FALSE)) {
return std::string(path);
}
}
return "";
}
// 创建快捷方式
bool CreateShortcut(const char* targetPath, const char* shortcutPath, const char* description = NULL) {
CoInitialize(NULL);
IShellLinkA* pShellLink = NULL;
HRESULT hr = CoCreateInstance(
CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLinkA,
(LPVOID*)&pShellLink
);
if (SUCCEEDED(hr)) {
IPersistFile* pPersistFile = NULL;
pShellLink->SetPath(targetPath);
if (description) {
pShellLink->SetDescription(description);
}
hr = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
if (SUCCEEDED(hr)) {
wchar_t wsz[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, shortcutPath, -1, wsz, MAX_PATH);
hr = pPersistFile->Save(wsz, TRUE);
pPersistFile->Release();
}
pShellLink->Release();
}
CoUninitialize();
if (SUCCEEDED(hr)) {
printf("[+] Created shortcut: %s\n", shortcutPath);
return true;
} else {
printf("[-] Failed to create shortcut\n");
return false;
}
}
// 添加启动文件夹自启动
bool AddStartupFolderAutorun(const char* appName, const char* appPath, bool allUsers = false) {
std::string startupPath = GetStartupFolderPath(allUsers);
if (startupPath.empty()) {
printf("[-] Failed to get startup folder path\n");
return false;
}
std::string shortcutPath = startupPath + "\\" + std::string(appName) + ".lnk";
return CreateShortcut(appPath, shortcutPath.c_str(), appName);
}
// 删除启动文件夹自启动
bool RemoveStartupFolderAutorun(const char* appName, bool allUsers = false) {
std::string startupPath = GetStartupFolderPath(allUsers);
if (startupPath.empty()) {
return false;
}
std::string shortcutPath = startupPath + "\\" + std::string(appName) + ".lnk";
if (DeleteFileA(shortcutPath.c_str())) {
printf("[+] Removed startup shortcut: %s\n", appName);
return true;
}
return false;
}
// 列出启动文件夹内容
void ListStartupFolder(bool allUsers = false) {
std::string startupPath = GetStartupFolderPath(allUsers);
if (startupPath.empty()) {
return;
}
printf("\n[%s] Startup Folder Contents:\n", allUsers ? "All Users" : "Current User");
printf("----------------------------------------\n");
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA((startupPath + "\\*").c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (strcmp(findData.cFileName, ".") != 0 &&
strcmp(findData.cFileName, "..") != 0) {
printf("%s\n", findData.cFileName);
}
} while (FindNextFileA(hFind, &findData));
FindClose(hFind);
}
}
3. 服务自启动
// service_autorun.cpp
// 服务自启动实现
#include <windows.h>
#include <stdio.h>
// 安装服务
bool InstallService(const char* serviceName, const char* displayName, const char* binaryPath) {
SC_HANDLE hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!hSCManager) {
printf("[-] Failed to open SC Manager\n");
return false;
}
SC_HANDLE hService = CreateServiceA(
hSCManager,
serviceName,
displayName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
binaryPath,
NULL,
NULL,
NULL,
NULL,
NULL
);
if (hService) {
printf("[+] Service installed: %s\n", serviceName);
// 启动服务
StartServiceA(hService, 0, NULL);
printf("[+] Service started\n");
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return true;
} else {
printf("[-] Failed to create service\n");
CloseServiceHandle(hSCManager);
return false;
}
}
// 删除服务
bool UninstallService(const char* serviceName) {
SC_HANDLE hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCManager) {
return false;
}
SC_HANDLE hService = OpenServiceA(hSCManager, serviceName, SERVICE_STOP | DELETE);
if (!hService) {
CloseServiceHandle(hSCManager);
return false;
}
// 停止服务
SERVICE_STATUS status;
ControlService(hService, SERVICE_CONTROL_STOP, &status);
// 删除服务
bool result = DeleteService(hService);
if (result) {
printf("[+] Service uninstalled: %s\n", serviceName);
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return result;
}
// 查询服务状态
void ListServices() {
SC_HANDLE hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (!hSCManager) {
return;
}
DWORD bytesNeeded, servicesReturned, resumeHandle = 0;
// 第一次调用获取所需缓冲区大小
EnumServicesStatusA(
hSCManager,
SERVICE_WIN32,
SERVICE_STATE_ALL,
NULL,
0,
&bytesNeeded,
&servicesReturned,
&resumeHandle
);
// 分配缓冲区
LPBYTE buffer = new BYTE[bytesNeeded];
if (EnumServicesStatusA(
hSCManager,
SERVICE_WIN32,
SERVICE_STATE_ALL,
(LPENUM_SERVICE_STATUSA)buffer,
bytesNeeded,
&bytesNeeded,
&servicesReturned,
&resumeHandle
)) {
LPENUM_SERVICE_STATUSA services = (LPENUM_SERVICE_STATUSA)buffer;
printf("\nServices:\n");
printf("----------------------------------------\n");
for (DWORD i = 0; i < servicesReturned; i++) {
const char* state = "Unknown";
switch (services[i].ServiceStatus.dwCurrentState) {
case SERVICE_RUNNING: state = "Running"; break;
case SERVICE_STOPPED: state = "Stopped"; break;
case SERVICE_PAUSED: state = "Paused"; break;
}
printf("%-20s %-15s %s\n",
services[i].lpServiceName,
state,
services[i].lpDisplayName);
}
}
delete[] buffer;
CloseServiceHandle(hSCManager);
}
4. 计划任务自启动
// scheduled_task.cpp
// 计划任务自启动实现
#include <windows.h>
#include <taskschd.h>
#include <comdef.h>
#include <stdio.h>
#pragma comment(lib, "taskschd.lib")
// 创建计划任务
bool CreateScheduledTask(const char* taskName, const char* executablePath) {
CoInitialize(NULL);
ITaskService* pService = NULL;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService
);
if (FAILED(hr)) {
CoUninitialize();
return false;
}
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
if (FAILED(hr)) {
pService->Release();
CoUninitialize();
return false;
}
ITaskFolder* pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
if (FAILED(hr)) {
pService->Release();
CoUninitialize();
return false;
}
// 创建任务定义
ITaskDefinition* pTask = NULL;
hr = pService->NewTask(0, &pTask);
if (FAILED(hr)) {
pRootFolder->Release();
pService->Release();
CoUninitialize();
return false;
}
// 设置注册信息
IRegistrationInfo* pRegInfo = NULL;
pTask->get_RegistrationInfo(&pRegInfo);
pRegInfo->put_Author(_bstr_t(L"System"));
pRegInfo->Release();
// 设置触发器
ITriggerCollection* pTriggerCollection = NULL;
pTask->get_Triggers(&pTriggerCollection);
ITrigger* pTrigger = NULL;
pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
pTrigger->Release();
pTriggerCollection->Release();
// 设置动作
IActionCollection* pActionCollection = NULL;
pTask->get_Actions(&pActionCollection);
IAction* pAction = NULL;
pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
IExecAction* pExecAction = NULL;
pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction);
_bstr_t path(executablePath);
pExecAction->put_Path(path);
pExecAction->Release();
pAction->Release();
pActionCollection->Release();
// 注册任务
IRegisteredTask* pRegisteredTask = NULL;
hr = pRootFolder->RegisterTaskDefinition(
_bstr_t(taskName),
pTask,
TASK_CREATE_OR_UPDATE,
_variant_t(),
_variant_t(),
TASK_LOGON_INTERACTIVE_TOKEN,
_variant_t(L""),
&pRegisteredTask
);
if (SUCCEEDED(hr)) {
printf("[+] Scheduled task created: %s\n", taskName);
}
if (pRegisteredTask) pRegisteredTask->Release();
pTask->Release();
pRootFolder->Release();
pService->Release();
CoUninitialize();
return SUCCEEDED(hr);
}
// 删除计划任务
bool DeleteScheduledTask(const char* taskName) {
CoInitialize(NULL);
ITaskService* pService = NULL;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService
);
if (FAILED(hr)) {
CoUninitialize();
return false;
}
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
if (FAILED(hr)) {
pService->Release();
CoUninitialize();
return false;
}
ITaskFolder* pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
if (FAILED(hr)) {
pService->Release();
CoUninitialize();
return false;
}
hr = pRootFolder->DeleteTask(_bstr_t(taskName), 0);
if (SUCCEEDED(hr)) {
printf("[+] Scheduled task deleted: %s\n", taskName);
}
pRootFolder->Release();
pService->Release();
CoUninitialize();
return SUCCEEDED(hr);
}
5. 统一自启动管理器
// autorun_manager.cpp
// 统一自启动管理器
#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
// 自启动方法枚举
enum class AutorunMethod {
RegistryCurrentUser,
RegistryLocalMachine,
StartupFolderCurrentUser,
StartupFolderAllUsers,
Service,
ScheduledTask
};
// 自启动管理器
class AutorunManager {
private:
std::string m_appName;
std::string m_appPath;
public:
AutorunManager(const char* appName, const char* appPath)
: m_appName(appName), m_appPath(appPath) {}
// 添加自启动
bool AddAutorun(AutorunMethod method) {
switch (method) {
case AutorunMethod::RegistryCurrentUser:
return AddRegistryAutorun(m_appName.c_str(), m_appPath.c_str(), false);
case AutorunMethod::RegistryLocalMachine:
return AddRegistryAutorun(m_appName.c_str(), m_appPath.c_str(), true);
case AutorunMethod::StartupFolderCurrentUser:
return AddStartupFolderAutorun(m_appName.c_str(), m_appPath.c_str(), false);
case AutorunMethod::StartupFolderAllUsers:
return AddStartupFolderAutorun(m_appName.c_str(), m_appPath.c_str(), true);
case AutorunMethod::Service: {
std::string serviceName = "AutoRun_" + m_appName;
return InstallService(serviceName.c_str(), m_appName.c_str(), m_appPath.c_str());
}
case AutorunMethod::ScheduledTask: {
std::string taskName = "AutoRun_" + m_appName;
return CreateScheduledTask(taskName.c_str(), m_appPath.c_str());
}
}
return false;
}
// 移除自启动
bool RemoveAutorun(AutorunMethod method) {
switch (method) {
case AutorunMethod::RegistryCurrentUser:
return RemoveRegistryAutorun(m_appName.c_str(), false);
case AutorunMethod::RegistryLocalMachine:
return RemoveRegistryAutorun(m_appName.c_str(), true);
case AutorunMethod::StartupFolderCurrentUser:
return RemoveStartupFolderAutorun(m_appName.c_str(), false);
case AutorunMethod::StartupFolderAllUsers:
return RemoveStartupFolderAutorun(m_appName.c_str(), true);
case AutorunMethod::Service: {
std::string serviceName = "AutoRun_" + m_appName;
return UninstallService(serviceName.c_str());
}
case AutorunMethod::ScheduledTask: {
std::string taskName = "AutoRun_" + m_appName;
return DeleteScheduledTask(taskName.c_str());
}
}
return false;
}
// 列出所有自启动项
void ListAllAutoruns() {
printf("========================================\n");
printf(" Autorun Items Summary \n");
printf("========================================\n");
ListRegistryAutorun(false); // HKCU
ListRegistryAutorun(true); // HKLM
ListStartupFolder(false); // Current User
ListStartupFolder(true); // All Users
ListServices();
}
};
// 测试函数
void TestAutorun() {
printf("=== Autorun Test ===\n");
char appPath[MAX_PATH];
GetModuleFileNameA(NULL, appPath, MAX_PATH);
AutorunManager manager("TestApp", appPath);
// 测试添加自启动
printf("[*] Adding registry autorun (current user)...\n");
manager.AddAutorun(AutorunMethod::RegistryCurrentUser);
printf("[*] Adding startup folder autorun...\n");
manager.AddAutorun(AutorunMethod::StartupFolderCurrentUser);
// 显示当前自启动项
manager.ListAllAutoruns();
// 测试移除
printf("\n[*] Removing autorun items...\n");
manager.RemoveAutorun(AutorunMethod::RegistryCurrentUser);
manager.RemoveAutorun(AutorunMethod::StartupFolderCurrentUser);
printf("[*] Test completed\n");
}
int main() {
printf("========================================\n");
printf(" Autorun Implementation Demo \n");
printf("========================================\n\n");
TestAutorun();
return 0;
}
6、课后作业
6.1、作业1:实现多方法组合自启动
设计一个能够同时使用多种方法确保自启动的机制。
6.2、作业2:添加自启动隐蔽性
实现隐藏自启动项的方法,避免被安全软件轻易发现。
6.3、作业3:实现自启动检测和清除
开发一个工具,能够检测和清除各种自启动项。