Les services Windows en Win32

Développement système natif en c/c++ avec win32 ...

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 46
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

Les services Windows en Win32

Post by Hydraxx »

Salut, :D

aujourd’hui on va voir un pilier du système Windows en Win32 : les services.

C’est un sujet très important en développement système, parce que énormément de composants réels du système ou des logiciels de sécurité reposent dessus. Antivirus, agents EDR, services de mise à jour, collecteurs de logs, brokers, services réseau, superviseurs, lanceurs de tâches, composants d’entreprise… tous utilisent d’une manière ou d’une autre le modèle des services Windows.

Le problème, c’est que beaucoup de développeurs connaissent vaguement le mot “service”, savent qu’on peut en créer un avec CreateServiceW, mais ne comprennent pas vraiment le modèle complet. Or un service n’est pas juste un EXE “sans interface”. C’est un programme géré par le Service Control Manager, avec un cycle de vie précis, des états, un compte d’exécution, des contrôles, des obligations vis-à-vis du système, et souvent des contraintes de sécurité importantes.

Pourquoi les services sont un sujet fondamental

Comprendre les services Windows permet de mieux voir :
  • comment Windows exécute du code en arrière-plan sur la durée
  • comment un programme peut démarrer avant meme qu’un utilisateur ouvre sa session
  • comment le SCM supervise le cycle de vie d’un service
  • comment démarrer, arrêter, configurer et interroger un service proprement
  • comment choisir le bon compte d’exécution
  • comment gérer la sécurité, les droits et les dépendances
  • comment écrire un vrai service Win32 robuste au lieu d’un simple programme “qui tourne en boucle”
Autrement dit, les services sont une brique centrale du système d’exploitation.

Ce qu’est réellement un service Windows

Un service Windows est un processus, ou plus exactement un programme conçu pour etre géré par Windows via le Service Control Manager, souvent abrégé SCM.

Un service se distingue d’une application classique par plusieurs propriétés :
  • il peut démarrer sans utilisateur connecté
  • il s’exécute en arrière-plan
  • son cycle de vie est géré par le SCM
  • il peut etre lancé automatiquement au boot selon sa configuration
  • il doit signaler son état au système
  • il n’est pas conçu pour interagir directement avec l’utilisateur comme une application GUI classique
Il faut donc bien retenir ceci : un service reste un programme user-mode, souvent un EXE classique du point de vue binaire, mais ce programme respecte un modèle d’exécution particulier.

Services et applications classiques : la différence de logique

Une application classique est généralement lancée par un utilisateur, depuis l’explorateur, une console, un raccourci, ou un autre programme. Elle vit dans la session utilisateur, possède souvent une interface, et son cycle de vie est lié à la logique de l’utilisateur ou de la session.

Un service, lui, suit une logique différente :
  • il est lancé par le système via le SCM
  • il peut continuer à tourner sans aucune session utilisateur active
  • il appartient au monde du fond de tâche, pas à celui de l’interface
  • il doit gérer correctement démarrage, arrêt, pause éventuelle et shutdown système
  • il est pensé pour durer et pour etre robuste
C’est pour ça qu’un service ne doit pas etre conçu comme un simple “main avec une boucle infinie”.

Le Service Control Manager : centre de contrôle des services

Le composant central de ce modèle est le Service Control Manager, ou SCM.

Le SCM sert notamment à :
  • maintenir la base de configuration des services
  • démarrer les services
  • les arrêter
  • leur envoyer des commandes de contrôle
  • interroger leur état
  • gérer certaines dépendances
  • appliquer des politiques de sécurité et de démarrage
Tous les services Windows passent d’une manière ou d’une autre par lui. C’est donc l’interlocuteur obligatoire du développeur dès qu’il veut manipuler les services proprement.

Ouvrir le Service Control Manager

Pour interagir avec la base des services, il faut d’abord ouvrir le SCM :

Code: Select all

SC_HANDLE hSCM = OpenSCManagerW(
    NULL,
    NULL,
    SC_MANAGER_ALL_ACCESS
);

if (!hSCM)
    return 1;
SC_HANDLE est un handle spécifique au monde des services. Ce n’est pas un HANDLE générique fermé avec CloseHandle. Il doit etre fermé avec :
  • CloseServiceHandle
C’est un point important. Les objets du SCM ont leur propre famille de fonctions.

Exemple :

Code: Select all

CloseServiceHandle(hSCM);
Il faut aussi savoir que le SCM est protégé. Certaines opérations demandent des droits élevés, surtout pour créer, supprimer ou reconfigurer un service.

Parmi les droits SCM importants :
  • SC_MANAGER_CONNECT
  • SC_MANAGER_CREATE_SERVICE
  • SC_MANAGER_ENUMERATE_SERVICE
  • SC_MANAGER_LOCK
  • SC_MANAGER_QUERY_LOCK_STATUS
  • SC_MANAGER_MODIFY_BOOT_CONFIG
  • SC_MANAGER_ALL_ACCESS
Comme toujours, mieux vaut demander exactement ce qui est nécessaire.

Créer un service avec CreateServiceW

L’API de base pour enregistrer un service est :
  • CreateServiceW
Exemple :

Code: Select all

SC_HANDLE hService = CreateServiceW(
    hSCM,
    L"MyService",
    L"My Service",
    SERVICE_ALL_ACCESS,
    SERVICE_WIN32_OWN_PROCESS,
    SERVICE_AUTO_START,
    SERVICE_ERROR_NORMAL,
    L"C:\\Path\\service.exe",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
);

if (!hService)
    return 1;
Cette fonction enregistre le service dans la base du SCM. Elle ne “fait pas tourner” le service immédiatement. Elle crée sa configuration persistante.

Parmi les paramètres à bien comprendre :
  • le nom de service, utilisé en interne par le SCM
  • le display name, plus lisible pour l’humain
  • les droits d’accès demandés sur le service créé
  • le type du service
  • le type de démarrage
  • le contrôle d’erreur
  • le chemin du binaire
  • le groupe de chargement éventuel
  • les dépendances
  • le compte du service
  • le mot de passe associé si nécessaire
Types de services

Le type du service décrit comment il s’exécute. Parmi les valeurs importantes :
  • SERVICE_WIN32_OWN_PROCESS
  • SERVICE_WIN32_SHARE_PROCESS
  • SERVICE_KERNEL_DRIVER
  • SERVICE_FILE_SYSTEM_DRIVER
  • SERVICE_USER_SERVICE
  • SERVICE_INTERACTIVE_PROCESS
Pour le développement user-mode Win32 classique, les deux types les plus importants sont :
  • SERVICE_WIN32_OWN_PROCESS : le service tourne dans son propre processus
  • SERVICE_WIN32_SHARE_PROCESS : plusieurs services partagent un meme processus hote
SERVICE_INTERACTIVE_PROCESS existe historiquement, mais il faut faire très attention : les services modernes sont isolés en Session 0, et l’interaction graphique directe avec l’utilisateur n’est plus le modèle normal.

Types de démarrage

Le mode de démarrage est lui aussi crucial.

Les grandes valeurs à connaitre :
  • SERVICE_BOOT_START
  • SERVICE_SYSTEM_START
  • SERVICE_AUTO_START
  • SERVICE_DEMAND_START
  • SERVICE_DISABLED
Dans le monde user-mode, les plus fréquentes sont surtout :
  • SERVICE_AUTO_START
  • SERVICE_DEMAND_START
  • SERVICE_DISABLED
SERVICE_AUTO_START signifie que le service doit démarrer automatiquement via le système. SERVICE_DEMAND_START signifie qu’il est démarré à la demande. SERVICE_DISABLED le rend non démarrable tant qu’il n’est pas reconfiguré.

Il faut aussi connaitre la notion de delayed auto-start, gérée via une configuration supplémentaire et non via une simple valeur de démarrage.

Le contrôle d’erreur

CreateServiceW prend aussi un type de sévérité pour l’échec de démarrage :
  • SERVICE_ERROR_IGNORE
  • SERVICE_ERROR_NORMAL
  • SERVICE_ERROR_SEVERE
  • SERVICE_ERROR_CRITICAL
Cette partie est surtout importante pour les composants réellement critiques du système. Dans beaucoup de services applicatifs, SERVICE_ERROR_NORMAL est le cas courant.

Ouvrir un service existant

Si le service existe déjà, on l’ouvre avec :
  • OpenServiceW
Exemple :

Code: Select all

SC_HANDLE hService = OpenServiceW(
    hSCM,
    L"MyService",
    SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP
);

if (!hService)
    return 1;
Là encore, il faut demander les bons droits.

Parmi les droits service importants :
  • SERVICE_QUERY_CONFIG
  • SERVICE_CHANGE_CONFIG
  • SERVICE_QUERY_STATUS
  • SERVICE_ENUMERATE_DEPENDENTS
  • SERVICE_START
  • SERVICE_STOP
  • SERVICE_PAUSE_CONTINUE
  • SERVICE_INTERROGATE
  • SERVICE_USER_DEFINED_CONTROL
  • DELETE
  • SERVICE_ALL_ACCESS
Démarrer un service

Pour démarrer un service déjà enregistré :

Code: Select all

if (!StartServiceW(hService, 0, NULL))
    return 1;
Si le service accepte des arguments de démarrage, ils peuvent etre fournis ici.

Il est ensuite fréquent d’interroger son état pour savoir s’il est réellement passé à SERVICE_RUNNING, au lieu de supposer que l’appel suffit.

Arrêter un service

Pour demander l’arrêt d’un service :

Code: Select all

SERVICE_STATUS status = { 0 };

if (!ControlService(
    hService,
    SERVICE_CONTROL_STOP,
    &status))
{
    return 1;
}
Cette commande ne “tue” pas le service directement. Elle envoie un contrôle stop. Ensuite, c’est au service de réagir correctement, de faire son nettoyage, puis de signaler son nouvel état au SCM.

Il faut donc bien distinguer :
  • la demande d’arrêt
  • l’arrêt effectif
Le cycle de vie d’un service

Un service Win32 n’est pas un simple processus qui tourne librement. Il possède un cycle de vie explicite, avec des états bien connus.

Les états les plus importants sont :
  • SERVICE_STOPPED
  • SERVICE_START_PENDING
  • SERVICE_STOP_PENDING
  • SERVICE_RUNNING
  • SERVICE_CONTINUE_PENDING
  • SERVICE_PAUSE_PENDING
  • SERVICE_PAUSED
Le service doit notifier le SCM à chaque changement important d’état, sinon le système finit par considérer que le service ne respecte pas correctement le protocole attendu.

SERVICE_STATUS et SERVICE_STATUS_PROCESS

Deux structures très importantes reviennent souvent :
  • SERVICE_STATUS
  • SERVICE_STATUS_PROCESS
SERVICE_STATUS est la structure de base utilisée pour signaler un état ou recevoir certains retours simples.

Ses champs importants incluent notamment :
  • dwServiceType
  • dwCurrentState
  • dwControlsAccepted
  • dwWin32ExitCode
  • dwServiceSpecificExitCode
  • dwCheckPoint
  • dwWaitHint
SERVICE_STATUS_PROCESS est une structure plus riche, utilisée notamment avec QueryServiceStatusEx. Elle ajoute par exemple :
  • dwProcessId
  • dwServiceFlags
Elle est très utile pour connaitre le PID du processus hébergeant le service.

Le vrai point d’entrée : StartServiceCtrlDispatcherW

Un service ne démarre pas comme une application classique où main ou wmain ferait tout librement du début à la fin. Le programme service doit se connecter au SCM via :
  • StartServiceCtrlDispatcherW
Exemple :

Code: Select all

SERVICE_TABLE_ENTRYW serviceTable[] =
{
    { (LPWSTR)L"MyService", ServiceMain },
    { NULL, NULL }
};

if (!StartServiceCtrlDispatcherW(serviceTable))
    return 1;
Cette fonction connecte le processus service au SCM et lui fournit la table des services gérés.

La structure importante ici est :
  • SERVICE_TABLE_ENTRYW
Elle associe un nom de service à une fonction ServiceMain.

Dans un cas simple, il n’y a qu’un service dans le processus. Dans un cas partagé, un meme processus peut héberger plusieurs services.

ServiceMain : le point d’entrée du service

Le SCM appelle ensuite :

Code: Select all

void WINAPI ServiceMain(
    DWORD argc,
    LPWSTR* argv
);
C’est ici que le service :
  • s’initialise
  • enregistre son handler de contrôle
  • signale ses changements d’état
  • crée ses threads de travail éventuels
  • commence sa logique réelle
ServiceMain doit etre pensée comme le point d’entrée logique du service, pas comme un simple détail administratif.

Enregistrer le handler de contrôle

Pour recevoir les commandes du SCM, le service doit enregistrer un handler.

La forme moderne à privilégier est :
  • RegisterServiceCtrlHandlerExW
Il existe aussi :
  • RegisterServiceCtrlHandlerW
mais la version Ex est plus riche.

Exemple :

Code: Select all

SERVICE_STATUS_HANDLE g_StatusHandle = RegisterServiceCtrlHandlerExW(
    L"MyService",
    ServiceCtrlHandlerEx,
    NULL
);

if (!g_StatusHandle)
    return;
La structure ou plutôt le type important ici est :
  • SERVICE_STATUS_HANDLE
Il représente le lien logique entre le service et le SCM pour les mises à jour d’état.

Les contrôles que peut recevoir un service

Le handler peut recevoir différents contrôles, parmi lesquels :
  • SERVICE_CONTROL_STOP
  • SERVICE_CONTROL_PAUSE
  • SERVICE_CONTROL_CONTINUE
  • SERVICE_CONTROL_INTERROGATE
  • SERVICE_CONTROL_SHUTDOWN
  • SERVICE_CONTROL_PARAMCHANGE
  • SERVICE_CONTROL_NETBINDADD
  • SERVICE_CONTROL_NETBINDREMOVE
  • SERVICE_CONTROL_DEVICEEVENT
  • SERVICE_CONTROL_SESSIONCHANGE
  • SERVICE_CONTROL_POWEREVENT
Tous les services ne traitent pas tous ces contrôles, mais il faut au moins connaitre les principaux.

Le service déclare ce qu’il accepte via le champ dwControlsAccepted dans SERVICE_STATUS.

Flags importants :
  • SERVICE_ACCEPT_STOP
  • SERVICE_ACCEPT_PAUSE_CONTINUE
  • SERVICE_ACCEPT_SHUTDOWN
  • SERVICE_ACCEPT_PARAMCHANGE
  • SERVICE_ACCEPT_SESSIONCHANGE
  • SERVICE_ACCEPT_POWEREVENT
SetServiceStatus : obligation centrale

L’API fondamentale pour notifier le SCM est :
  • SetServiceStatus
Exemple typique :

Code: Select all

SERVICE_STATUS status = { 0 };
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = 0;
status.dwWin32ExitCode = NO_ERROR;
status.dwCheckPoint = 1;
status.dwWaitHint = 3000;

if (!SetServiceStatus(g_StatusHandle, &status))
    return;
Puis plus tard :

Code: Select all

status.dwCurrentState = SERVICE_RUNNING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;

SetServiceStatus(g_StatusHandle, &status);
Il faut bien comprendre la logique de dwCheckPoint et dwWaitHint pendant les états pending. Ils servent à indiquer au SCM que le service progresse encore et qu’il ne faut pas le considérer comme bloqué trop vite.

Bonne architecture d’un service

Une erreur classique consiste à bloquer ServiceMain avec toute la logique métier du service sans gérer proprement l’arrêt. Une architecture plus propre ressemble souvent à ceci :
  • ServiceMain s’enregistre auprès du SCM
  • ServiceMain signale SERVICE_START_PENDING
  • ServiceMain initialise les ressources essentielles
  • ServiceMain crée un thread worker ou une boucle de travail structurée
  • ServiceMain signale SERVICE_RUNNING
  • le handler reçoit STOP ou SHUTDOWN et déclenche un event d’arrêt
  • le worker termine proprement
  • le service signale SERVICE_STOPPED
On voit ici immédiatement le lien avec les objets de synchronisation Win32, surtout les events.

SERVICE_STATUS_HANDLE, worker thread et event d’arrêt

Dans beaucoup de services propres, on retrouve :
  • un SERVICE_STATUS_HANDLE global ou de contexte
  • un SERVICE_STATUS
  • un HANDLE d’event d’arrêt
  • un ou plusieurs threads de travail
Exemple d’event d’arrêt :

Code: Select all

HANDLE g_StopEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!g_StopEvent)
    return;
Le handler sur STOP fait souvent :

Code: Select all

SetEvent(g_StopEvent);
Puis le worker ou la boucle principale attend cet event ou le surveille.

C’est un schéma extrêmement classique dans les services Win32.

Interroger l’état d’un service

Pour connaitre l’état d’un service, plusieurs API existent. La plus simple historiquement :
  • QueryServiceStatus
La plus utile en pratique aujourd’hui :
  • QueryServiceStatusEx
Exemple :

Code: Select all

SERVICE_STATUS_PROCESS ssp = { 0 };
DWORD bytesNeeded = 0;

if (!QueryServiceStatusEx(
    hService,
    SC_STATUS_PROCESS_INFO,
    (LPBYTE)&ssp,
    sizeof(ssp),
    &bytesNeeded))
{
    return 1;
}
Cela permet notamment de récupérer :
  • l’état courant
  • les contrôles acceptés
  • le code de sortie
  • le PID du processus service
Configurer un service après création

Un service ne se limite pas à sa création initiale. Plusieurs API permettent de le reconfigurer.

Les plus importantes :
  • ChangeServiceConfigW
  • ChangeServiceConfig2W
  • QueryServiceConfigW
  • QueryServiceConfig2W
QueryServiceConfigW utilise la structure :
  • QUERY_SERVICE_CONFIGW
QueryServiceConfig2W permet d’obtenir ou définir d’autres blocs d’information plus riches.

Parmi les structures ou infos importantes autour de ChangeServiceConfig2W / QueryServiceConfig2W :
  • SERVICE_DESCRIPTIONW
  • SERVICE_FAILURE_ACTIONSW
  • SC_ACTION
  • SERVICE_DELAYED_AUTO_START_INFO
  • SERVICE_SID_INFO
  • SERVICE_REQUIRED_PRIVILEGES_INFOW
  • SERVICE_PRESHUTDOWN_INFO
  • SERVICE_TRIGGER_INFO
  • SERVICE_LAUNCH_PROTECTED_INFO
Cela montre que le monde des services est beaucoup plus riche qu’un simple nom + chemin binaire.

Description, actions en cas d’échec, delayed auto-start

Quelques exemples particulièrement utiles.

Pour définir une description lisible :
  • SERVICE_DESCRIPTIONW
Pour définir des actions en cas d’échec :
  • SERVICE_FAILURE_ACTIONSW
  • SC_ACTION
Ces structures permettent par exemple :
  • redémarrer le service
  • redémarrer la machine
  • ne rien faire
  • lancer une commande
Pour le delayed auto-start :
  • SERVICE_DELAYED_AUTO_START_INFO
Ce mode est très utile pour éviter de surcharger le démarrage trop tôt avec certains services non critiques.

Supprimer un service

Pour supprimer l’enregistrement d’un service :
  • DeleteService
Exemple :

Code: Select all

if (!DeleteService(hService))
    return 1;
Cela supprime l’entrée logique du service dans la base du SCM, mais il faut faire attention au moment exact où cela devient effectif, surtout si le service est encore en cours d’exécution.

Enumérer les services

Pour lister les services du système :
  • EnumServicesStatusExW
La structure importante ici est notamment :
  • ENUM_SERVICE_STATUS_PROCESSW
Cela permet d’obtenir pour chaque service des informations comme :
  • le nom
  • le display name
  • l’état
  • le PID si applicable
C’est très utile pour les outils d’administration ou de diagnostic.

Dépendances entre services

Les services peuvent dépendre d’autres services ou groupes de chargement. Cela fait partie de leur configuration.

API utiles autour de ce sujet :
  • EnumDependentServicesW
  • QueryServiceConfigW
Comprendre les dépendances est important, parce qu’un service peut refuser de démarrer si ce dont il dépend n’est pas disponible.

Le compte d’exécution du service

Un service tourne toujours sous un compte. C’est un point absolument central.

Les comptes courants sont notamment :
  • LocalSystem
  • LocalService
  • NetworkService
  • un compte utilisateur spécifique
  • un gMSA dans des contextes d’entreprise
Le compte choisi détermine :
  • les privilèges locaux
  • l’identité de sécurité
  • la capacité d’accès à certaines ressources
  • le comportement réseau
  • l’exposition en cas de compromission
Il faut résister à la tentation de mettre LocalSystem partout. C’est souvent trop puissant, donc trop risqué.

Services et tokens

Comme tout processus user-mode, un service s’exécute sous un token de sécurité. Ce token détermine :
  • ce qu’il peut lire
  • ce qu’il peut modifier
  • les privilèges dont il dispose
  • les processus qu’il peut ouvrir
  • les clés registre ou fichiers auxquels il peut accéder
Les services sont donc étroitement liés à tout ce qu’on a vu sur les tokens de sécurité.

API importantes de ce monde :
  • OpenProcessToken
  • GetTokenInformation
  • AdjustTokenPrivileges
  • DuplicateTokenEx
  • CreateProcessAsUserW
Dans beaucoup de services, surtout ceux qui agissent pour le compte d’un client ou qui lancent d’autres processus, cette partie devient centrale.

Session 0 isolation

Il faut aussi connaitre une notion très importante des services modernes : la Session 0 isolation.

Les services tournent généralement en Session 0, alors que les utilisateurs interactifs travaillent dans d’autres sessions. Cela implique notamment :
  • pas d’interface utilisateur classique directement visible pour l’utilisateur
  • pas de modèle “service interactif” normal comme autrefois
  • séparation claire entre code système et interface utilisateur
C’est pour ça qu’afficher une UI depuis un service est une très mauvaise idée dans le modèle moderne.

Types de notifications avancées et handler Ex

La version étendue du handler, RegisterServiceCtrlHandlerExW, permet de traiter plus de cas, avec un contexte plus riche.

On voit alors apparaitre des données liées à :
  • SESSIONCHANGE
  • POWEREVENT
  • DEVICEEVENT
Cela rend les services capables de réagir à des événements système plus variés.

Sécurité des services et des handles SCM

Les services eux-memes sont des objets sécurisés. Leur manipulation dépend donc des droits accordés.

API utiles à connaitre de nom autour de la sécurité des services :
  • QueryServiceObjectSecurity
  • SetServiceObjectSecurity
On retrouve ici la logique Windows classique : tokens, descripteurs de sécurité, ACL, et vérification d’accès.

Quelques structures importantes à connaitre

Pour avoir une bonne base dans le monde des services, il faut reconnaitre rapidement plusieurs structures.

Les plus importantes :
  • SERVICE_TABLE_ENTRYW
  • SERVICE_STATUS
  • SERVICE_STATUS_PROCESS
  • SERVICE_STATUS_HANDLE
  • STARTUPINFOW
  • PROCESS_INFORMATION
  • QUERY_SERVICE_CONFIGW
  • SERVICE_DESCRIPTIONW
  • SERVICE_FAILURE_ACTIONSW
  • SC_ACTION
  • SERVICE_DELAYED_AUTO_START_INFO
  • ENUM_SERVICE_STATUS_PROCESSW
  • SERVICE_REQUIRED_PRIVILEGES_INFOW
  • SERVICE_SID_INFO
  • SERVICE_PRESHUTDOWN_INFO
  • SERVICE_TRIGGER_INFO
Toutes n’apparaissent pas dans chaque projet, mais les reconnaitre change vraiment la lecture du code Win32 système.

Les API à connaitre absolument

Pour le SCM et l’ouverture :
  • OpenSCManagerW
  • CloseServiceHandle
  • OpenServiceW
Pour la création, suppression et configuration :
  • CreateServiceW
  • DeleteService
  • ChangeServiceConfigW
  • ChangeServiceConfig2W
  • QueryServiceConfigW
  • QueryServiceConfig2W
Pour le cycle de vie et l’état :
  • StartServiceW
  • ControlService
  • ControlServiceEx
  • QueryServiceStatus
  • QueryServiceStatusEx
  • SetServiceStatus
Pour le point d’entrée du service :
  • StartServiceCtrlDispatcherW
  • RegisterServiceCtrlHandlerW
  • RegisterServiceCtrlHandlerExW
Pour l’énumération et les dépendances :
  • EnumServicesStatusExW
  • EnumDependentServicesW
Pour la sécurité :
  • QueryServiceObjectSecurity
  • SetServiceObjectSecurity
Pour le lien avec les tokens et processus :
  • OpenProcessToken
  • GetTokenInformation
  • AdjustTokenPrivileges
  • CreateProcessAsUserW
Architecture minimale saine d’un service

Une architecture raisonnable pour un service Win32 ressemble souvent à ceci :
  • main ou wmain appelle StartServiceCtrlDispatcherW
  • ServiceMain s’enregistre avec RegisterServiceCtrlHandlerExW
  • le service signale SERVICE_START_PENDING
  • il crée ses ressources de base, notamment un event d’arrêt
  • il lance un ou plusieurs workers
  • il signale SERVICE_RUNNING
  • le handler reçoit STOP ou SHUTDOWN et signale la fin
  • les workers quittent proprement
  • le service fait son cleanup
  • il signale SERVICE_STOPPED
C’est une structure beaucoup plus robuste qu’un simple thread bloqué dans ServiceMain sans protocole clair.

Erreurs classiques

Comme souvent en Win32 système, les erreurs les plus gênantes viennent d’un mauvais modèle mental.

Parmi les fautes fréquentes :
  • vouloir afficher une vraie interface graphique depuis le service
  • bloquer ServiceMain sans stratégie d’arrêt propre
  • oublier de notifier le SCM avec SetServiceStatus
  • oublier CloseServiceHandle
  • mal choisir le compte du service
  • utiliser LocalSystem sans nécessité
  • ignorer Session 0 isolation
  • supposer qu’un StartServiceW signifie que le service est déjà totalement running
  • mal gérer les états pending, dwCheckPoint et dwWaitHint
  • oublier les dépendances ou la sécurité du service
Ce qu’il faut retenir

Un service Windows est un programme spécial géré par le Service Control Manager. Il n’est pas simplement “un EXE sans fenêtre”, mais un composant structuré avec un cycle de vie précis, un compte d’exécution, un état courant, des contrôles, et des obligations de notification vers le système.

Les idées essentielles à garder sont les suivantes :
  • le SCM est le centre de contrôle obligatoire
  • CreateServiceW enregistre un service, StartServiceW le démarre
  • le vrai point d’entrée logique du service passe par StartServiceCtrlDispatcherW puis ServiceMain
  • RegisterServiceCtrlHandlerExW et SetServiceStatus sont au coeur du protocole de fonctionnement
  • le service doit signaler correctement ses états
  • le compte d’exécution et le token déterminent les droits réels
  • Session 0 isolation interdit de raisonner comme pour une application GUI classique
Conclusion

Comprendre les services, c’est comprendre comment Windows exécute du code de manière durable, supervisée et structurée en arrière-plan. C’est aussi comprendre qu’un service n’est pas seulement une question d’API, mais un vrai modèle d’exécution avec gestion du cycle de vie, sécurité, comptes, dépendances et supervision par le SCM.

Si tu maitrises déjà correctement :
  • OpenSCManagerW
  • CreateServiceW
  • OpenServiceW
  • StartServiceW
  • ControlService
  • StartServiceCtrlDispatcherW
  • ServiceMain
  • RegisterServiceCtrlHandlerExW
  • SetServiceStatus
  • QueryServiceStatusEx
  • SERVICE_STATUS et SERVICE_STATUS_PROCESS
alors tu possèdes déjà une base sérieuse sur les services Windows.

Et surtout, tu commences à voir que les services sont l’un des grands cadres d’exécution permanents de Windows, au meme titre que les processus, les threads, les tokens ou les I/O.

A bientot pour le prochain cours :D

Who is online

Users browsing this forum: No registered users and 1 guest