| 当你从WindowsNT,2000,XP环境非正常退出重新启动系统时,你会注意到系统会自动运行一个磁盘检查程序AutoCheck,这个程序既不同于Windows 9X /Me环境下的ScanDisk.exe 16位DOS程序,也不同于Win32环境下的应用程序,它本身不能在Win32环境下加载运行,只能通过注册编辑表,由系统启动时自动加载,这种程序我们称之为Native NT应用程序。 |
| 编写Native (本机)NT应用程序有许多好处,因为程序加载时系统尚未完全启动起来,这个环境是一个相对比较干净的系统,你可以利用这个机会实现磁盘优化和查杀病毒,另一方面,由于这个程序能够自动加载,所以它可以自动帮我们做许多事情,比如显示一些的提示信息、进行系统初始化等等。 |
| 编写本机NT应用程序,并没有编写Win32应用程序容易,因为系统启动时,Win32 尚未启动起来,它无法使用Win32 SDK 函数,只能使用NTDLL.dll输出的1403个本机API函数(我用的是WindowsXP中的版本),使用的方法类似于我们编写WDM驱动程序使用内核服务,程序调试比较困难,甚至无法实现汉字输出,屏幕的输出不能通过窗口实现的,而是写在一个让人反感的蓝色屏幕上,种种劣迹,使得除了系统提供的磁盘检查程序外,很难觅得它的踪影,当然这与资料奇缺也很有关系,。但是由于它本身运行在Ring0层,接近系统内核,拥有没有限制操作权限,它可以读写任何端口,运行用户态无法运行的特权指令,相对于Win32 API函数也有它无法比拟的优点,而且大部分的Win 32 SDK都是通过调用NTDLL.DLL本机API间接实现的,几乎每一个Win32 SDK函数在本机API中都有它对应的版本,Kernel32(NT环境下)的输出函数基本都是NTDLL.DLL过渡产物。它的目的是保持与Windows9X有一样的输出函数,从而使编写的Win32应用程序能在同时在Windows 9X和NT两种环境下运行,而不用作任何修改。 |
| 本机NT应用程序的入口为NtProcessStartup,不同于Win32控制台的main函数,也不同于Win32 GUI界面的WinMain函数,程序运行结束,必须调用NtTerminateProcess结束本进程。 |
| 本机NT应用程序依靠系统自动加载,为了实现这一步,你必须首先把本机NT应用程序拷贝到Windows NT系统目录(system32),然后修改注册编辑表实现,修改时你既可以利用注册编辑器对下面键手工编辑,也可以创建一个如下的文件,进行导入。导入后重新启动系统即可生效,如果编写的程序因为错误无法正常运行,你可以在启动时,选择恢复最后一次正确配置。 |
| Windows Registry Editor Version 5.00 |
| [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager] |
| "BootExecute"=hex(7):61,00,75,00,74,00,6f,00,63,00,68,00,65,00,63,00,6b,00,20,\ |
| 00,61,00,75,00,74,00,6f,00,63,00,68,00,6b,00,20,00,2a,00,00,00,6e,00,61,00,\ |
| 74,00,69,00,76,00,65,00,20,00,57,00,65,00,6c,00,63,00,6f,00,6d,00,65,00,20,\ |
| 00,59,00,6f,00,75,00,20,00,54,00,6f,00,20,00,55,00,73,00,65,00,20,00,57,00,\ |
| 69,00,6e,00,64,00,6f,00,77,00,73,00,20,00,58,00,50,00,21,00,00,00,00,00 |
| native Welcome You To Use Windows XP! |
| 其中native是程序名称, Welcome You To Use Windows XP!为参数信息. |
| Windows Registry Editor Version 5.00 |
| [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager] |
| "BootExecute"=hex(7):61,00,75,00,74,00,6f,00,63,00,68,00,65,00,63,00,6b,00,20,\ |
| 00,61,00,75,00,74,00,6f,00,63,00,68,00,6b,00,20,00,2a,00,00,00,00,00 |
| 制作这样一个注册文件是非常麻烦的,你可以通过注册编辑器的导出功能先导出一个样板,然后对样板进行修改即可. |
| 下面是一个完整的NT本机应用程序的例子,在Visual Studio 6 环境下用DDK2000编译通过,连接后的程序,可以通过WindowsNT/2K/XP测试. |
| //====================================================================== |
| // 这是一个Native NT 演示程序,这个程序只能运行在Win32环境之外,必须依靠 |
| // 由NTDLL.DLL提供的原始服务,操作系统提供的AutoChk程序(系统引导时自动 |
| //运行的磁盘检查工具就是这样的一个Native NT应用程序。这样的程序广泛地应用 |
| //这是一个简单的Hello World 型的应用程序,它通过注册编辑表进行安装,安装后,在 |
| //系统引导时,回弹出一个蓝屏背景的提示信息,这个程序不能在Win32环境下运行. |
| //====================================================================== |
| #include "ntddk.h" // 包含了所有的Native 函数定义 |
| //---------------------------------------------------------------------- |
| // NtProcessStartup为Native NT应用程序的入口点,注意不是main 和WinMain |
| //---------------------------------------------------------------------- |
| void NtProcessStartup( PSTARTUP_ARGUMENT Argument ) |
| PUNICODE_STRING commandLine; |
| PWCHAR stringBuffer, argPtr; |
| UNICODE_STRING DisplayMessage; |
| RTL_HEAP_DEFINITION heapParams; |
| memset( &heapParams, 0, sizeof( RTL_HEAP_DEFINITION )); |
| heapParams.Length = sizeof( RTL_HEAP_DEFINITION ); |
| Heap = RtlCreateHeap( 2, 0, 0x100000, 0x1000, 0, &heapParams ); |
| commandLine = &Argument->Environment->CommandLine; |
| argPtr = commandLine->Buffer; |
| while( *argPtr != L' ' ) argPtr++; |
| stringBuffer = RtlAllocateHeap( Heap, 0, 256 ); |
| swprintf( stringBuffer, L"\n%s", argPtr ); |
| DisplayMessage.Buffer = stringBuffer; |
| DisplayMessage.Length = wcslen( stringBuffer ) * sizeof(WCHAR); |
| DisplayMessage.MaximumLength = DisplayMessage.Length + sizeof(WCHAR); |
| NtDisplayString( &DisplayMessage ); |
| RtlFreeHeap( Heap, 0, stringBuffer ); |
| NtTerminateProcess( NtCurrentProcess(), 0 ); |
| 编写本机NT应用程序,对大多数程序员来说是一个新概念,很多程序员甚至没有听说过这种应用程序,当然国内这方面的资料几乎没有,本文提供了全部的源程序,旨在抛砖引玉。 | |