【问题标题】:Writing a Windows NT subsystem [closed]编写 Windows NT 子系统 [关闭]
【发布时间】:2011-05-21 18:40:19
【问题描述】:

出于纯粹的教育目的,我想尝试在 Windows 7 上编写我自己的最小 NT 子系统——类似于 Microsoft 的基于 Unix 的应用程序的子系统中的 posix.exe 的基本等价物。

但我似乎找不到任何关于此主题的公开文档。子系统需要实现什么 API?它是如何在 Windows 中注册的?子系统镜像需要如何构建(PE头需要设置哪些标志等)?

我最想找到一本书或网站,其中包含整个主题的概述,甚至是其他人编写的“hello world”NT 子系统的源代码。但是,如果您能在这里指出我正确的方向,那么任何事情都会受到赞赏......

【问题讨论】:

  • 本机 API 未记录。
  • -1?这是个有趣的问题。仅仅因为没有人可能知道答案并不意味着它是一个糟糕的问题。
  • @Hans:无意冒犯,但这是人们就本机 API 给出的最烦人、最不具建设性和最不正确的 cmets 之一。例如,请参阅here
  • @Hans,来自那个 MSDN 页面:Note: If the call to this function occurs in user mode, you should use the name "NtOpenFile" instead of "ZwOpenFile". 这对我来说看起来像是用户模式 ​​API 的文档......虽然目前还不清楚它是否打算这样使用 :)
  • @bdonlan:感谢您在这里复制,这正是我所指的。 :) 还有像 this 这样的页面和其他页面,其中包含许多所谓的“未记录” API 的文档(尽管显然不是每个本地函数都记录在案)。

标签: windows subsystem windows-nt


【解决方案1】:

以下是子系统的主要组件:

  • 用户模式服务器。服务器创建一个 (A)LPC 端口并侦听和处理客户端请求。
  • 用户模式客户端 DLL。在 DLL_INIT_ROUTINE 中,您可以连接到服务器设置的端口。此 DLL 将公开您子系统的 API,并且某些功能需要与服务器通信。
  • 内核模式支持驱动程序(您可能不需要这个)。

您需要在服务器或驱动程序中存储进程或线程状态。如果您将它存储在服务器中,您可能需要NtRegisterThreadTerminatePort 之类的东西来确保您在进程或线程退出时进行清理。如果您使用的是驱动程序,则需要PsSetCreateProcessNotifyRoutine

最后,如果您使用的是 XP 或更低版本,则可以添加新的系统调用。您可以通过调用KeAddSystemServiceTable 来完成此操作。要从用户模式调用系统调用,您需要像这样创建存根(对于 x86):

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

在 Vista 及更高版本上,您不能再添加新的系统服务表,因为只有两个空间:内核的系统调用和 win32k 的系统调用。

经过一番谷歌搜索后,我发现了这个:http://winntposix.sourceforge.net/。我认为它与您正在寻找的非常相似,并且使用了我提到的很多东西。

【讨论】:

    【解决方案2】:

    我也沉迷于原生 API。 :)

    我很高兴地说,它远没有某些人认为的那样危险或无证。 :]

    “Hello, world”没有源代码,因为本机 API 与控制台交互并不容易,因为它是 Win32 子系统的一部分,需要客户端/服务器与端口进行通信。如果你需要编写一个控制台应用程序,你需要直接与 CSRSS 通信,它的消息格式没有记录(虽然它的一些格式可以在ReactOS's source 找到——如果你熟悉 ReactOS,它会给你带来很多好处) .

    我很快就会在这里发布一个你可能会感兴趣的例子;现在,请注意您的 only 选项是与 NTDLL.dll 链接,为此,您需要驱动程序开发工具包(因为您需要 lib 文件)。


    更新:看看这个!

    (我感觉没有人会发布像这样叛逆的东西。用原生 API 显示 GUI?!我一定是疯了!)

    #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;
    }
    

    如果您有任何问题,请随时提问!我不害怕原生 API! :)


    编辑 2:

    如果您尝试制作自己的 Kernel32 DLL 版本并像 Kernel32 对每个进程所做的那样加载它(因此是一个新的子系统),我只是想让您知道,我认为这是不可能的。它与我几天前询问的this question 非常相似,并且您似乎无法扩展 NT PE Loader 以了解新的子系统,所以我认为这是不可能的。

    【讨论】:

    • ReactOS 也是我的第一个想法。
    • @Uwe:是的,除了你在里面找不到这个特定的例子。 :) (顺便问一下,有谁知道如何使用
       来强制 C++ 语法高亮?)
    • 一个有趣的例子,但它似乎与创建一个实际的子系统有点相切,而不仅仅是一个原生子系统应用程序
    • 哈哈是的,我想我同意,它并没有真正回答我猜想的问题。不过,写这个答案很有趣! :)
    • 我知道这已经死了,但是因为它是在搜索我时出现的,所以我想加两分钱 - 它可以替换 Windows 中的 PE 加载程序,所以虽然你不能扩展它,但你可以替换它并将对常规 PE 文件的调用重定向到原始文件(我之前已经这样做了,以便在 DOSBox 中加载 16 位 EXE/COM 文件)。有一些奇怪的故障行为,但它确实有效。此外,您可能可以使用 ReactOS PE 加载程序,或者更可疑地尝试为它编译泄漏的 NT4 位。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    • 2016-09-14
    • 2011-11-19
    • 2013-08-18
    • 1970-01-01
    • 2012-03-23
    相关资源
    最近更新 更多