47 votes

Écriture d'un sous-système Windows NT

J'aimerais essayer d'écrire mon propre sous-système NT minimal sur Windows 7 à des fins purement éducatives -- quelque chose comme un équivalent de base du posix.exe dans le Subsystem for Unix-based Applications de Microsoft.

Mais je n'arrive pas à trouver de documentation publique sur ce sujet. Quelle API un sous-système doit-il implémenter ? Comment s'enregistre-t-il auprès de Windows ? Comment l'image du sous-système doit-elle être construite (quels drapeaux doivent être définis dans l'en-tête PE, etc.) ?

J'aimerais surtout trouver un livre ou un site web avec une vue d'ensemble du sujet, ou même le code source d'un sous-système NT "hello world" que quelqu'un d'autre a écrit. Mais n'importe quoi serait apprécié si vous pouviez m'indiquer la bonne direction...

18voto

wj32 Points 4505

Voici les principaux composants d'un sous-système :

  • Serveur en mode utilisateur. Le serveur crée un port (A)LPC et écoute et traite les demandes des clients.
  • DLL client en mode utilisateur. Dans la DLL_INIT_ROUTINE, vous pouvez vous connecter au port mis en place par le serveur. Cette DLL exposera l'API de votre sous-système, et certaines fonctions nécessiteront une communication avec le serveur.
  • Pilote de support en mode noyau (vous n'en aurez peut-être pas besoin).

Vous voudrez stocker l'état des processus ou des threads soit dans votre serveur, soit dans votre pilote. Si vous le stockez dans le serveur, vous aurez besoin de quelque chose comme NtRegisterThreadTerminatePort afin de s'assurer de faire le ménage lorsqu'un processus ou un thread se termine. Si vous utilisez un pilote, vous avez besoin de PsSetCreateProcessNotifyRoutine .

Enfin, si vous êtes sous XP et moins, vous pouvez ajouter de nouveaux appels système. Vous pouvez le faire en appelant KeAddSystemServiceTable . Pour invoquer les appels système en mode utilisateur, vous devez créer des stubs comme ceci (pour x86) :

; XyzCreateFooBar(__out PHANDLE FooBarHandle, __in ACCESS_MASK DesiredAccess, ...)
mov     eax, SYSTEM_CALL_NUMBER
mov     edx, 0x7ffe0300
call    [edx]
retn    4

Sur Vista et les versions ultérieures, vous ne pouvez plus ajouter de nouvelles tables de services système car il n'y a de place que pour deux d'entre elles : les appels système du noyau et les appels système de win32k.

Après un peu de recherche sur Google, j'ai trouvé ceci : http://winntposix.sourceforge.net/ . Je pense qu'il est très similaire à ce que vous recherchez, et utilise beaucoup des choses que j'ai mentionnées.

13voto

Mehrdad Points 70493

Je suis aussi obsédé par l'API native :)

Et je suis heureux de dire que c'est loin d'être aussi dangereux ou sans papiers que certaines personnes le font croire :]

Il n'y a pas de code source pour "Hello, world" parce que l'API native n'interagit pas si facilement avec la console, puisqu'elle fait partie du sous-système Win32 et nécessite une communication client/serveur avec des ports. Si vous avez besoin d'écrire une application console, vous devez communiquer directement avec le CSRSS, dont les formats de messages ne sont pas documentés (bien que certains de ses formats puissent être trouvés dans le fichier Les sources de ReactOS -- cela vous ferait beaucoup de bien de vous familiariser avec ReactOS).

Je publierai bientôt ici un exemple qui pourrait vous intéresser ; pour l'instant, sachez que votre uniquement La seule option possible est de lier avec NTDLL.dll, et pour cela, vous avez besoin du Driver Development Kit (puisque vous avez besoin du fichier lib).


Mise à jour : Regardez ça !

(J'ai le sentiment que personne d'autre ne postera quelque chose d'aussi rebelle que cela. Montrer une interface graphique avec l'API native ? ! Je dois être fou !)

#include <Windows.h>

typedef DWORD NTSTATUS;

//These are from ReactOS
typedef enum _HARDERROR_RESPONSE_OPTION
{
    OptionAbortRetryIgnore,
    OptionOk,
    OptionOkCancel,
    OptionRetryCancel,
    OptionYesNo,
    OptionYesNoCancel,
    OptionShutdownSystem
} HARDERROR_RESPONSE_OPTION, *PHARDERROR_RESPONSE_OPTION;

typedef enum _HARDERROR_RESPONSE
{
    ResponseReturnToCaller,
    ResponseNotHandled,
    ResponseAbort,
    ResponseCancel,
    ResponseIgnore,
    ResponseNo,
    ResponseOk,
    ResponseRetry,
    ResponseYes,
    ResponseTryAgain,
    ResponseContinue
} HARDERROR_RESPONSE, *PHARDERROR_RESPONSE;

typedef struct _UNICODE_STRING {
    USHORT  Length;
    USHORT  MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

//You'll need to link to NTDLL.lib
//which you can get from the Windows 2003 DDK or any later WDK
NTSYSAPI VOID NTAPI RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,
    IN PCWSTR SourceString);
NTSYSAPI NTSTATUS NTAPI NtRaiseHardError(IN NTSTATUS ErrorStatus,
    IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask,
    IN PULONG_PTR Parameters,
    IN HARDERROR_RESPONSE_OPTION ValidResponseOptions,
    OUT PHARDERROR_RESPONSE Response);
#define STATUS_SERVICE_NOTIFICATION_2 0x50000018

int main()
{
    HARDERROR_RESPONSE response;
    ULONG_PTR items[4] = {0};
    UNICODE_STRING text, title;
    RtlInitUnicodeString(&text,
        L"Hello, NT!\r\nDo you like this?\r\n"
        L"This is just about as pretty as the GUI will get.\r\n"
        L"This message will self-destruct in 5 seconds...");
    RtlInitUnicodeString(&title, L"Native Message Box!");
    items[0] = (ULONG_PTR)&text;
    items[1] = (ULONG_PTR)&title;
    items[2] = (ULONG_PTR)OptionYesNo;
    items[3] = (ULONG_PTR)5000;
    NtRaiseHardError(STATUS_SERVICE_NOTIFICATION_2, ARRAYSIZE(items),
        0x1 | 0x2 /*First two parameters are UNICODE_STRINGs*/, items,
        OptionOk /*This is ignored, since we have a custom message box.*/,
        &response);
    return 0;
}

Si vous avez des questions, n'hésitez pas à les poser ! Je n'ai pas peur de l'API native ! :)


Edit 2 :

Si vous essayez de créer votre propre version DLL de Kernel32 et de la faire charger comme Kernel32 le fait avec chaque processus (donc un nouveau sous-système), je voulais juste vous faire savoir que je ne pense pas que ce soit possible. C'est plutôt similaire à cette question que j'ai demandé il y a quelques jours, et il semble que vous ne pouvez pas étendre le chargeur PE de NT pour connaître les nouveaux sous-systèmes, donc je ne pense pas que ce sera possible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X