Давненько не было статей, но это не потому что я забил. Просто нужно было набрать немного материалов и идей для написания. Знаете бывает у нас программеров такой «творческий кризис». Думаю скоро пройдет, но в это время буду по немногу продолжать писать.
Вся информация предоставляется исключительно в ознакомительных целях. Автор не несет ответственности за любой возможный вред причиненный материалами данной статьи.
Ну в общем добрый вечер =)
Раньше меня многие спрашивали как поднять процесс до системного, сейчас смотрю все уже забили на этот вопрос. Но так как мейнстримом это не стало, думаю пора приоткрыть занавес и показать один из нескольких способов, и объяснить некоторые нюансы.
Система Windows так устроена что запустить процесс с определенными привилегиями может только процесс (или пользователь) имеющий не меньшие привилегии. То есть по сути мы не система а всего лишь (максимум) администратор и запустить процесс мы можем только с правами администратора.
Но как заставить систему запускать процесс саму?
В этом нам помогут службы windows.
Их система запускает сама и выполняются они от имени системы, это дает нам некоторое поле для маневров. Например как я уже говорил что только системный процесс может запустить другой процесс с системными правами (не будем брать в учет некоторые баги\фичи винды).
Сегодня мы напишем службу которая будет запускать наш процесс и следить чтобы его некто не смог закрыть (если кто не знал то системные процессы тоже можно закрывать).
Создаем новый проект и пишем нашу функцию мейн (в случае сервиса у нас будет SvcMain) и дополнительные функции для установки и удаления сервиса.
Создаем файл work.cpp и пишем код который будет выполнять наша служба.
В данном файле мы ищем нужный нам процесс в цикле и если не находим то запускаем его (svc_worker.exe)
Таким образом мы не даем закрыть процесс.
Вы спросите зачем нам следить за файлом если процесс системный и закрыть его не даст сама система? Об этом чуть ниже…
Когда программа работает из под системы то функции типо получить директорию аппдата и т.д. получают путь не пользователя, а путь системной папки аппдата. Когда служба запускает наш ехе то автоматически директория работы нашей программы является C:\\windows\system32 процессы этой директории (если они системные) закрыть не получится, но если мы сменили рабочую директорию на директорию пользователя (например командой _chdir) то наш процесс хоть и работает от имени системы, но уязвим к закрытию из обычного диспетчера. Это кстати одна из особенностей работы из под системы.
Да, знаю немного не прокомментировал код, но я думаю что вы уже немного разбираетесь, если что-то не понятно по коду смело пишите мне, но код службы в данном случае практически стандартный с минимальным функционалом.
Для запуска нашей службы достаточно открыть командную строку от имени администратора и выполнить команду «[название службы] install»
Либо написать отдельную программу для установки сервиса. Код самой установки есть в коде выше. Надеюсь разберетесь.
Вся информация предоставляется исключительно в ознакомительных целях. Автор не несет ответственности за любой возможный вред причиненный материалами данной статьи.
Ну в общем добрый вечер =)
Раньше меня многие спрашивали как поднять процесс до системного, сейчас смотрю все уже забили на этот вопрос. Но так как мейнстримом это не стало, думаю пора приоткрыть занавес и показать один из нескольких способов, и объяснить некоторые нюансы.
Система Windows так устроена что запустить процесс с определенными привилегиями может только процесс (или пользователь) имеющий не меньшие привилегии. То есть по сути мы не система а всего лишь (максимум) администратор и запустить процесс мы можем только с правами администратора.
Но как заставить систему запускать процесс саму?
В этом нам помогут службы windows.
Их система запускает сама и выполняются они от имени системы, это дает нам некоторое поле для маневров. Например как я уже говорил что только системный процесс может запустить другой процесс с системными правами (не будем брать в учет некоторые баги\фичи винды).
Сегодня мы напишем службу которая будет запускать наш процесс и следить чтобы его некто не смог закрыть (если кто не знал то системные процессы тоже можно закрывать).
Создаем новый проект и пишем нашу функцию мейн (в случае сервиса у нас будет SvcMain) и дополнительные функции для установки и удаления сервиса.
C++:
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <array>
#include <string>
#pragma comment(lib, "advapi32.lib")
#define SVCNAME TEXT("MicrosoftAlphaVite4")
SERVICE_STATUS gSvcStatus;
SERVICE_STATUS_HANDLE gSvcStatusHandle;
HANDLE ghSvcStopEvent = NULL;
VOID SvcInstall(void);
VOID SvcUninstall(void);
VOID SvcWork(void);
VOID WINAPI SvcCtrlHandler(DWORD);
VOID WINAPI SvcMain(DWORD, LPTSTR *);
VOID ReportSvcStatus(DWORD, DWORD, DWORD);
VOID SvcInit(DWORD, LPTSTR *);
void __cdecl _tmain(int argc, TCHAR *argv[])
{
if (lstrcmpi(argv[1], TEXT("install")) == 0)
{
SvcInstall();
return;
}
else if (lstrcmpi(argv[1], TEXT("uninstall")) == 0)
{
SvcUninstall();
return;
}
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(DispatchTable))
{
}
}
VOID SvcInstall()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH];
if (!GetModuleFileName(NULL, szPath, MAX_PATH))
{
return;
}
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS);
if (NULL == schSCManager)
{
return;
}
schService = CreateService(
schSCManager, // SCM database
SVCNAME, // name of service
SVCNAME, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szPath, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
CloseServiceHandle(schSCManager);
return;
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
VOID SvcUninstall(void)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS);
if (NULL == schSCManager)
{
return;
}
schService = OpenService(
schSCManager,
SVCNAME,
DELETE);
if (schService == NULL)
{
CloseServiceHandle(schSCManager);
return;
}
if (!DeleteService(schService));
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME, SvcCtrlHandler);
if (!gSvcStatusHandle)
{
return;
}
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
SvcInit(dwArgc, lpszArgv);
}
VOID SvcInit(DWORD dwArgc, LPTSTR *lpszArgv)
{
ghSvcStopEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL);
if (ghSvcStopEvent == NULL)
{
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
while (TRUE)
{
SvcWork();
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
}
VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
gSvcStatus.dwCurrentState = dwCurrentState;
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
gSvcStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
gSvcStatus.dwControlsAccepted = 0;
else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED))
gSvcStatus.dwCheckPoint = 0;
else gSvcStatus.dwCheckPoint = dwCheckPoint++;
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
}
VOID WINAPI SvcCtrlHandler(DWORD dwCtrl)
{
switch (dwCtrl)
{
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
Создаем файл work.cpp и пишем код который будет выполнять наша служба.
C++:
#include <windows.h>
#include <tchar.h>
#include <wtsapi32.h>
#include <userenv.h>
#include <stdio.h>
#include <direct.h>
#include <iostream>
#include <array>
#include <string>
#pragma comment(lib, "wtsapi32")
#pragma comment(lib, "userenv")
//функция поиска процесса
int GetProcessByName(const char* process_name)
{
WTS_PROCESS_INFO* pWPIs = NULL;
DWORD dwProcCount = 0;
if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, NULL, 1, &pWPIs, &dwProcCount))
{
//Go through all processes retrieved
for (DWORD i = 0; i < dwProcCount; i++)
{
if (_stricmp(pWPIs[i].pProcessName, process_name) == 0)
{
return 1;
}
//pWPIs[i].pProcessName = process file name only, no path!
//pWPIs[i].ProcessId = process ID
//pWPIs[i].SessionId = session ID, if you need to limit it to the logged in user processes
//pWPIs[i].pUserSid = user SID that started the process
}
}
//Free memory
if (pWPIs)
{
WTSFreeMemory(pWPIs);
pWPIs = NULL;
}
return 0;
}
VOID SvcWork()
{
std::string systemDrive = getenv("SystemDrive");
systemDrive = systemDrive + "\\";
_chdir(systemDrive.c_str());
//выполняем цикл пока процесс не будет запущен
HANDLE hToken = NULL;
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
WTSQueryUserToken(dwSessionId, &hToken);
while (true)
{
if (GetProcessByName("svc_worker.exe") == 0)
{
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = TEXT("winsta0\\default");
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
PVOID lpEnvironment = NULL;
CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE);
LPTSTR szCmdline = _tcsdup(_T("\"svc_worker.exe\""));
CreateProcessAsUser(hToken,
NULL,
szCmdline,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS | DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
lpEnvironment,
NULL,
&si,
&pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Sleep(5000);
}
CloseHandle(hToken);
}
Таким образом мы не даем закрыть процесс.
Вы спросите зачем нам следить за файлом если процесс системный и закрыть его не даст сама система? Об этом чуть ниже…
Когда программа работает из под системы то функции типо получить директорию аппдата и т.д. получают путь не пользователя, а путь системной папки аппдата. Когда служба запускает наш ехе то автоматически директория работы нашей программы является C:\\windows\system32 процессы этой директории (если они системные) закрыть не получится, но если мы сменили рабочую директорию на директорию пользователя (например командой _chdir) то наш процесс хоть и работает от имени системы, но уязвим к закрытию из обычного диспетчера. Это кстати одна из особенностей работы из под системы.
Да, знаю немного не прокомментировал код, но я думаю что вы уже немного разбираетесь, если что-то не понятно по коду смело пишите мне, но код службы в данном случае практически стандартный с минимальным функционалом.
Для запуска нашей службы достаточно открыть командную строку от имени администратора и выполнить команду «[название службы] install»
Либо написать отдельную программу для установки сервиса. Код самой установки есть в коде выше. Надеюсь разберетесь.
Последнее редактирование: