百度空间 | 百度首页 
               
 
查看文章
 
深入Native应用程序
2006-10-26 17:29

深入Native应用程序

版权所有 1998 Mark Russinovich

 

翻译:MJ0011

最后更新:1998年2月8日


导言

如果你对WindowsNt结构有一定的了解,你可能会知道,Win32应用程序所使用的API,并非是"真正"的NT API

。POSIX,OS/2和Win32,这些WindowsNT操作系统环境,使用他们自己的API同他们的客户应用程序进行交流,

但却使用NT "native" API同 WindowsNT进行交流.这些native API大部分都是未公开的(undocumented)。大

约只有25个API(包含250种功能)在WindowsNT设备驱动开发工具包(Device Driver Kit)里有所描述。


尽管绝大多数人都不知道,但"native"应用程序的确存在与WindowsNT上,他们在操作环境上没有任何客户程

序. 这些程序交流着native nt API并且不能使用任何操作环境API比如 Win32. 为什么这样一种程序是必须

的呢?因为在Win32子系统启动之前(大约在登陆对话框出现时)只可以运行native应用程序.最常见的native

应用程序的例子是"autochk"程序,他在初始化兰色登陆屏幕前运行 chkdsk(程序在屏幕上打印一串".")。

当然,Win32应用程序环境服务程序:CSRSS.exe(客户-服务运行时间子系统),也是一个native应用程序

在这篇文章里,我将会讲述如何构造一个native应用程序以及它们是如何工作的,同时我也会提供一个

native应用程序的示例源代码。这个示例很容易安装,它会在启动时的兰色屏幕打印一段你指定的字符串


Autochk是如何被执行的

Autochk在当内存分页被打开,Windows启动和系统开始驱动被载入之间的时间内运行。在这个时间点 启动顺

序会话管理器(smss.exe)进入windowsNT用户模式,并且没有任何程序被启动
注册表中:HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute
一个MULTI_SZ类型的键值
这里存放着将被会话管理器所执行的程序名称和参数
通常Autochk后加*号作为其参数"

Autocheck Autochk *
;名称 程序名 参数

会话管理器在<winnt>\system32目录下查找该值列出的可执行程序.当Autochk运行时,没有任何文件被打开

,所以Autochk可以用raw模式打开任何一个驱动器卷(包括根驱动器),并操作其磁盘数据结构.之后的任何

时间点都无法进行类似这样的操作

编译Native应用程序
微软没有提供相应的文档,但是NT DDK构建器知道如何去生成一个native应用程序,而且它可以被用来编译

autochk程序.和编写设备驱动程序一样,你必须指定SOURCE文件中的信息来定义应用程序。然而和编写驱动

不同的时,你在SOURCE文件中要求生成一个native应用程序需要这样定义:

TARGETTYPE=PROGRAM

构建器使用一个标准的makefile来进行向导:\ddk\inc\makefile.def 在编译native应用程序时会查找名为

nt.lib的运行库。不幸的是,微软并没在DDK上装载这个文件(在windows Server 2003 DDK里包括了这个文

件,但是我怀疑你用这个版本来连接你的native应用程序是无法运行在WindowsXP或win2000上的)
不管怎样,你可以忽略这个错误,方法是加入一行不考虑nt.lib,而指定visual c++的运行库msvcrt.lib到

makefile.lib中

如果你在DDK的"Checked Build"环境下进行编译,将会在%BASEDIR%\lib\%CPU%\Checked(例如

c:\ddk\lib\i386\checked\native.exe)产生一个包含了全部调试信息的native应用程序。如果你在"Free 

Build"环境中编译,你会在%BASEDIR%\lib\%CPU%\Free得到一个释出版本的程序.这些和构造设备驱动程序

放置的位置是一样的。

Native应用程序有着".exe"的扩展名,但是你不能象 win32的.exe文件那样去运行它,如果你在WIN32环境

下运行下,将会得到如下提示:

"<应用程序名> 应用程序无法在Win32模式中运行。"

深入学习一个native应用程序

native应用程序的入口点是NtProcessStartup,类似winmain或main.不同于其他的 Win32入口点的是,

native应用程序提供一个数据结构来存放它的唯一的参数来定位命令行参数

大多数的native应用程序的运行环境是由WindowsNt的native API输出库---NTDLL.DLL提供的。native应用

程序必须使用RtlCreateHeap(一个ntdll函数)来创建他们自己的堆来分配存储,使用RtlAllocateHeap来分

配内存以及用RtlFreeHeap来释放内存。native应用程序需要使用NtDisplayString 函数才可以打印想要的

内容到屏幕上(将被输出到初始化时的兰色屏幕上)


Native应用程序不象win32程序那样简单地从他们的启动函数返回,你需要调用NtProcessTerminate函数来

结束它的进程

NTDLL运行包含了数百个函数允许native应用程序执行文件I/O,与设备驱动进行相连,并执行进程间通讯。

不幸的是,他们大部分都是未公开的。

一个native应用程序的例子
我创建一个“玩具”native 应用程序用来演示native应用程序是如何构建的以及他们是如何工作的。运行

install.bat来安装native程序。批处理程序复制native.exe到你的<winnt>\system32目录并在注册表中增

加一个BootExecute的入口点:


native Hello World!


当你重新启动时,会话管理器运行完autochk后就会执行native。native分配一些堆,定位它的命令行参数

并打印参数("Hello world!")到兰色屏幕上,它所使用的函数上面已说过了。如果你想要打印其他的简单内

容,可以编辑BootExecute值使用regedit或regedit32,修改"Hello world"为你想要的信息

运行uinstall.bat可以卸载这个native执行程序。它从<winnt>\system32目录删除native.exe,并修改

BootExecute值为通常的值


如果你想要构建native程序你必须要用Windows设备驱动工具包(DDK),复制makefile.def到 \ddk\inc然后你

可以运行构建

 

=========================================================
Native.H

//======================================================================
//
// Native.h
//
// Mark Russinovich
// http://www.ntinternals.com
//
// This file includes the definitions required by the Native.exe sample
// NT native program to do what it does. 
//
//======================================================================

//
// Environment information, which includes command line and
// image file name
//
typedef struct {
       ULONG            Unknown[21];     
       UNICODE_STRING   CommandLine;
       UNICODE_STRING   ImageFile;
} ENVIRONMENT_INFORMATION, *PENVIRONMENT_INFORMATION;

//
// This structure is passed as NtProcessStartup's parameter
//
typedef struct {
       ULONG                     Unknown[3];
       PENVIRONMENT_INFORMATION  Environment;
} STARTUP_ARGUMENT, *PSTARTUP_ARGUMENT;

//
// Data structure for heap definition. This includes various
// sizing parameters and callback routines, which, if left NULL,
// result in default behavior
//
typedef struct {
 ULONG     Length;
 ULONG     Unknown[11];
} RTL_HEAP_DEFINITION, *PRTL_HEAP_DEFINITION;

//
// Native NT api function to write something to the boot-time
// blue screen
//
NTSTATUS 
NTAPI 
NtDisplayString(
  PUNICODE_STRING String 
  );

//
// Native applications must kill themselves when done - the job
// of this native API
//
NTSTATUS 
NTAPI 
NtTerminateProcess(
     HANDLE ProcessHandle, 
     LONG ExitStatus 
     );

//
// Definition to represent current process
//
#define NtCurrentProcess() ( (HANDLE) -1 )

//
// Heap creation routine
//
HANDLE 
NTAPI 
RtlCreateHeap(
       ULONG Flags, 
       PVOID BaseAddress, 
       ULONG SizeToReserve, 
       ULONG SizeToCommit, 
       PVOID Unknown,
       PRTL_HEAP_DEFINITION Definition
       );

//
// Heap allocation function (ala "malloc")
//
PVOID 
NTAPI 
RtlAllocateHeap(
  HANDLE Heap, 
  ULONG Flags, 
  ULONG Size 
  );

//
// Heap free function (ala "free")
//
BOOLEAN 
NTAPI 
RtlFreeHeap(
     HANDLE Heap, 
     ULONG Flags, 
     PVOID Address 
     );

=========================================================================
Native.C

//======================================================================
//
// Native.c
//
// Mark Russinovich
// http://www.ntinternals.com
//
// This is a demonstration of a Native NT program. These programs
// run outside of the Win32 environment and must rely on the raw
// services provided by NTDLL.DLL. AUTOCHK (the program that executes
// a chkdsk activity during the system boot) is an example of a
// native NT application.
//
// This example is a native 'hello world' program. When installed with
// the regedit file associated with it, you will see it print 
// "hello world" on the initialization blue screen during the system
// boot. This program cannot be run from inside the Win32 environment.
//
//======================================================================
#include "ntddk.h" // include this for its native functions and defn's
#include "stdio.h"
#include "native.h"

//
// Our heap
//
HANDLE Heap;

//----------------------------------------------------------------------
//
// NtProcessStartup
//
// Instead of a 'main' or 'winmain', NT applications are entered via
// this entry point.  
//
//----------------------------------------------------------------------
void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
{
    PUNICODE_STRING commandLine;
    PWCHAR stringBuffer, argPtr;
    UNICODE_STRING helloWorld;
    RTL_HEAP_DEFINITION  heapParams;

    //
    // Initialize some heap
    //
    memset( &heapParams, 0, sizeof( RTL_HEAP_DEFINITION ));
    heapParams.Length = sizeof( RTL_HEAP_DEFINITION );
    Heap = RtlCreateHeap( 2, 0, 0x100000, 0x1000, 0, &heapParams );

    //
    // Point at command line
    //
    commandLine = &Argument->Environment->CommandLine;

    //
    // Locate the argument
    //
    argPtr = commandLine->Buffer;
    while( *argPtr != L' ' ) argPtr++;
    argPtr++;

    //
    // Print out the argument
    //
    stringBuffer = RtlAllocateHeap( Heap, 0, 256 );
    swprintf( stringBuffer, L"\n%s", argPtr );
    helloWorld.Buffer = stringBuffer;
    helloWorld.Length = wcslen( stringBuffer ) * sizeof(WCHAR);
    helloWorld.MaximumLength = helloWorld.Length + sizeof(WCHAR);
    NtDisplayString( &helloWorld );

    //
    // Free heap
    //
    RtlFreeHeap( Heap, 0, stringBuffer );

    //
    // Terminate
    //
    NtTerminateProcess( NtCurrentProcess(), 0 );
}

===========================================================================

Install.bat

@echo off
copy native.exe %systemroot%\system32\.
regedit /s add.reg
echo Native Example Installed


=============================================================================
uinstall.bat

@echo off
del %systemroot%\system32\native.exe
regedit /s remove.reg
echo Native Example Uninstalled

 

 


类别:默认分类 | 添加到搜藏 | 浏览() | 评论 (15)
 
最近读者:
 
网友评论:
1
2006-10-26 17:33 | 回复
先占沙发,然后慢慢看。。。
 
2
2006-10-26 17:33 | 回复
===================================================================== ADD.reg REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager] "BootExecute"=hex(7):61,75,74,6f,63,68,65,63,6b,20,61,75,74,6f,63,68,6b,20,2a,\ 00,6e,61,74,69,76,65,20,48,65,6c,6c,6f,20,57,6f,72,6c,64,21,00,00 ====================================================================== REMOVE.reg REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager] "BootExecute"=hex(7):61,75,74,6f,63,68,65,63,6b,20,61,75,74,6f,63,68,6b,20,2a,\ 00,00
 
3
2007-01-03 12:38 | 回复
你太厉害了,很少见到有如此厉害电脑水平的女孩子,呵呵,加我qq112611196,探讨,我是gg
 
4
2007-01-05 09:43 | 回复
其实SMSS是NT系统的第一个用户进程,它的主要作用是承上启下,是系统引导的重要环节,WIN32子系统需要它加载(当然它也加载POSIX子系统,如果你选择POSIX子系统的话),在子系统加载之前的启动的用户程序都只能是NATIVE的,BOOTEXECUTE只是在子系统启动之前加载的用户程序的方法之一,另外还有其它平常看不到的键值可以启动NATIVE程序。退一步说,即使是WIN32子系统加载完成后,你基本上也无法加载与用户交互的WIN32的应用程序,你要等到WORKSTATION/DESTTOP创建后才可以启动交互式WIN32程序,而这个工作是由WINLOGON完成的。
 
5
2007-01-05 10:16 | 回复
构建NATIVE程序不是一定要NT.LIB,NT.LIB的作用仅是提供了启动代码,而且是一简单的启动代码,它仅完成了创建堆和命令行分析,然后就调用main函数。由于它没有调用_cinit类似的初始操作,因此你有要初始化的全局变量,则你要小心,你必须在你的代码中显式地初始化操作。从这个角度来说,NT.LIB不用也罢,自己写一个以后更简单些。DDK最好安装,可以免去自已做许多定义。 NATIVE程序完全可以在VC的集成环境中完成编写和编译,但要适当地设置编译选项,最重要的两点是:1、输出的IMAGE必须是NATIVE的;2、不能使用C库。
 
6
2007-01-05 16:10 | 回复
楼上也许觉得粘一段东西过来很显水平?
 
7
2007-01-05 22:26 | 回复
呵呵,看来我理解错了,这是楼主的地盘,自然只允许楼主表演了,原本希望能交流一下。对不起,打扰了!
 
8
2007-01-07 22:42 | 回复
愿博主:千秋万载,一统江湖!
 
9
2007-01-08 15:52 | 回复
先收藏了,呵呵
 
10
2007-01-16 17:03 | 回复
妹妹.你太牛X了.佩服
 
11
2007-01-24 17:12 | 回复
文章还行,但离深还是太远了吧
 
12
2007-03-07 02:11 | 回复
楼主和ostrich 说的东西都有用! 谢谢!
 
13
2007-06-20 15:56 | 回复
LZ太小气了。。。。
 
14
2008-06-09 14:29 | 回复
编译环境架设不起来,老是提示native.h没有找到。。,这个文件哪里来的
 
15
2008-06-16 16:05 | 回复
想问一下...~为什么 我用ddk 2000的编译环境来编译在Windows 2000下可以运行,而用用2003的free build出来在2003下不能运行呢?
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu