首页
论坛
课程
招聘
microdebug
雪    币: 336
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:280 )
在线值:
发帖
23
回帖
212
粉丝
0

[原创]native app开发小结

2010-7-30 15:12 26547

[原创]native app开发小结

2010-7-30 15:12
26547
没什么技术含量,开发小结而已。

Native app 程序开发
                        By microDebug
程序类型

关于程序级别的分类,大概可以分为三层:
应用层程序,即普通的APP程序;
Native App程序,如常见的chkdsk工具,PQ分区工具等,都属于这类,它是在win子系统未启动起来就执行的程序,执行环境比较纯净,只能调用ntdll.dll导出的函数;
Driver 内核驱动程序,因功能不同也分为若干类,如设备驱动程序,内核扩展程序,文件系统驱动,过滤驱动等,同属于内核态程序;
其中,native app在项目开发中用的较少,所用的函数接口MS也均未公开,开发难度和驱动相当,所以很少有人问津。但是,事实上,在某些应用场景下,用native app来实现是非常完美的,比如:接管winodws的开机启动界面和密码输入界面,需要native app;在开机前,执行磁盘修复,需要native app;开机前,执行杀毒,或者磁盘整理,因为此时环境比较纯净,需要native app。诸如此类~
最近,开发一个Native App项目,其规模和复杂度也不一般。期间遇到很多问题,在逐一解决的时候也收获了很多东西。现在略作整理,以备将来查用,二来与大家分享之~

Native app 基本工作原理

这里,只想简单的描述下。
Windows的设计是基于分层模型的,在设计之初,内核NT支持三个子系统,OS/2,posix,win32,这些子系统同属于一个层面上,它们公用windows nt提供的系统API和例程。其中,在某一个子系统上的API调用,都会经过NT”native”API同windowsNT进行通信。这些native API就是ntdll.dll导出的函数,因为它导出的大部分函数都只是起一个从子系统到NT内核的转发传递作用,所以也成为stub函数,这些函数的原型大多是未公开的,在早期的DDK里会有相关的描述,但是现在没了,取而代之的是内核实现的zw*,nt*开头的驱动函数。这里表明了MS的一个态度,不希望第三方在native app上干涉windows的太多工作,比如,接管了开机启动系统,接管了登录密码界面:D. 后来,因为种种历史原因,对OS/2和posix子系统的支持逐渐被淡忘。但是这种分层模型仍然存在,native app就是工作在子系统未启动之前,此时的系统环境很纯净,权限也相对较高;另外,对操作系统来说,支持native app也是一种必须,因为在子系统启动之前,很多功能的程序只能以native app来呈现,比如登录界面,CSRSS~
具体的启动时机:
Native app由启动会话管理器(smss.exe)来启动,如果想通知smss来执行一个native app程序,只需要修改一个注册表项,smss在每次启动的时候会去检查该项,确保该项下面的每个native app程序依次执行。注册表项为:HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute ,其类型为MULTI_SZ, 又是MS玩的一种字符串类型—多字符串类型,也就是说,这个MULTI_SZ字符串包含多个以\0结尾的子字符串,而整个字符串以\0\0结尾。在该注册表项后面添加要注册的native 程序名和参数就可以了。
关于native app的更多详细介绍,可以参考Mark Russinovich的一篇关于native的文章。

开发相关
Native app程序结构
Native app程序结构很简单,就好像我们写hello world,需要写一个main函数入口一样,native app的入口函数是NtProcessStartup,形如:
void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
其中,参数PSTARTUP_ARGUMENT是一个结构体,用来存放传入参数。
程序退出时,主动调用函数NtProcessTerminate退出,它不会像普通应用程序一样一个返回return就退出了。
基本的结构就是这样了:
void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
{
        // do something else
        NtProcessTerminate( NtCurrentProcess(), 0 );
}
当然现在还没有包含头文件之类的。
开发语言及第三方的库
        Native app支持的开发语言有C/ASM/C++,并且完美的支持C++的类特性,不过要像编写驱动一样,需要重载new,delete等内存分配函数。
        在内存使用上,可以使用两套接口:堆函数接口,以及虚拟内存函数接口,但是根据我的经验,使用堆函数接口,更高效并且内存bug出现的频率会大大降低。举个例子:我在调试native app的时候,一切正常,且全部通过,但是双机调试的时候,功能代码都运行完了,在子系统起来的时候,提示memory_corruption错误,这个问题整整找了好几天都没有找到,到最后,无意间屏蔽掉了系统的DbgPrint函数,memory错误才解决。其原因是,native gui图形模块的debug消息打印的太快太频繁,导致调试缓冲被溢出,当屏蔽了系统DbgPrint的时候,也就是在windbg 下bp DbgPrint,然后a eip,ret后,就正常了。虽然这个现象和程序无关,但是,用了虚拟内存的话,这个问题会更加容易重现。关于这个问题的重现很容易,就是在native 环境下双机调试,target机器一直打印消息,当打印到10W条以上时,调试缓冲就“爆”了。这真不知道是ms的bug,还是自己~~
       
关于new,delete的重载。
使用堆函数过程如下:首先创建一个全局堆,然后在这个全局堆上分配和释放局部堆。
HANDLE hGlobalHeap = NULL; // for globle call
void* __cdecl operator new(size_t size)
{
        if(hGlobalHeap == NULL)
                return NULL;
        return RtlAllocateHeap(hGlobalHeap,0/*HEAP_ZERO_MEMORY*/,size);
}
void __cdecl operator delete(void* addr)
{
        if(hGlobalHeap && addr) (void)RtlFreeHeap(hGlobalHeap,0,addr);
}
       
        关于NDK:前面说到,native app用的是ntdll.dll的导出函数,而这些函数MS并没有公开接口声明,那么我们使用的时候,首先必须要自己定义函数声明。NDK就是这样的一个类库,它几乎定义了ntdll.dll导出的全部函数的声明以及一些常用的数据结构的定义,我们只需要包含相应的头文件,导入ntdll.lib库,就可以像使用普通的API函数一样开发native app了。
        关于DLL:native app可以调用同一级别的DLL,使大型的项目开发更加容易,更加容易划分模块。注意,DLL的编译环境要和native app一致。
        关于native app的编译:可以选择用vs环境,也可以用DDK/WDK,但是推荐使用WDK。用VS环境的话,需要简单的设置下,随意创建一个类型的工程,然后修改Linker->system->Native,就可以了。如果用WDK编译,需要写一个SOURCE模板,如:
TARGETNAME=defrag
TARGETPATH=obj
TARGETTYPE=PROGRAM
INCLUDES=$(PUBLIC_ROOT)\inc\ddk
SOURCES=defrag.cpp
        注意:上面说的DLL的编译环境和native app的编译环境要一致,指的是不要用WDK编译的native去尝试链接VS编译的DLL,反之亦然。

Native GUI
在native app执行环境下画界面是不可行的,但是不是说做不到。
前面说了,可以写一个native app来接管windows的启动界面和密码输入界面,那么这个界面是如何画的呢?也有从驱动里实现的。但是,事实上,MS提供了一个native级别的动态库,名为:Bootvid.dll,用来实现GUI启动屏幕的引导视频驱动,这个dll导出了一些函数,可以实现画图,贴图功能,当然,这些函数接口仍然是未公开的。呵呵~
另外,在native app程序,可以利用一个函数向屏幕打印输出字符串,名为:
        //NTSTATUS
        //NTAPI NtDisplayString( PUNICODE_STRING String);
但是,事实上,这个函数已经不推荐使用了,在用WDK编译native app的时候,会提示一个警告信息,deprecated~~

Native app的灵活性
native app由于受到调用函数接口未公开,以及开发难度和调试难度不小的原因,很少有项目问津,但是,事实上,它仍然是一种工作于ring3的用户态程序,只是在子系统启动之前运行,所以,native app程序一般不会引起系统蓝屏的问题。也正是如此,native 程序工作在一个相对纯净的环境下,可以访问任何文件,甚至搬移MFT,系统元文件等。
        Ntdll.dll为native app导出的函数虽少,但是可以完成很多的功能。这些导出函数,基本上和内核的系统例程都是一一对应的。结合其他的模块,driver,应用程app,在加之native独特的运行环境和执行能力,往往会达到一个良好的效果。在这里,仅仅是一个普及~

具体应用及实例
        在开发native app之前,我想,最好有开发驱动的基础。因为native app程序的编写规范基本上和驱动一样,除了入口函数,调试方法也一样,必须要双机调试。当然,只是说编写规则一样,驱动特有的函数例程以及工作原理,二者是毫不相干的。举个例子,操作注册表,文件IO,线程创建,内存使用,二者基本上是一致的,具体的在使用中自己体会吧。
作为入门例子
作为入门我想还是用Mark Russinovich的例子吧,就好像Hello World的作用一样,让你真切的感受下native app程序。该程序在系统启动时,蓝屏界面上输出一行字符串信息。程序在附件,没什么过多的需要解释的。

实际开发
实际开发中,有不少的应用例子。比如,影子系统的启动界面,PQ分区工具,win系统自带的chkdsk工具,都属于这类程序。
下面说下自己的一些经历吧:
项目中有个需要,对特定文件进行磁盘整理。我们知道,文件系统导出了一组函数接口,用于对磁盘上的文件进行搬移操作,使文件内碎片和外碎片减少,提高IO吞吐率和磁盘访问率。唯一的限制是,pagefile.sys和日志文件不能整理,其他的文件,如MFT,系统元文件都可以整理。对于文件整理,更重要的是算法和稳定法,当然,这是另外一个话题了。根据prefreth原理,一个应用程序的工作集页面在运行时基本上是趋于稳定的,那么这些稳定的页面如果位于不同的文件(可能是链接库之类),且这些文件在磁盘上比较分散,那么就会影响程序的启动时间了,虽然prefretch做了改善,会自动的激发系统的磁盘整理来对“相关”的文件紧密排放,但仍然是不够的。所以,关于这种性能的改善看起来微乎其微,但是做好了,价值是不可估量的。这仅仅是一个方面,当然,项目中的主要目的并不是这个,虽然也是为了提高性能。
在native app下操作文件,考虑的情况是比较单一的,不会担心文件或目录被锁,从而出现不能访问的情况,也不会考虑过多的并发问题。所以,功能会更加集中,运行效率会更高,操作的空间和权限也更大。
仅限于此,就到这吧~~
                                                        By microdebug

DOC格式粘贴在这里,咋就这么乱?
可参考:http://hi.baidu.com/316526334/blog
native_back.rar
native app.doc
上传的附件:
最新回复 (31)
stu
雪    币: 1259
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
14
回帖
179
粉丝
0
stu 活跃值 2010-7-30 17:07
2
0
谢谢楼主分享。
zysyyz
雪    币: 2864
活跃值: 活跃值 (21)
能力值: ( LV4,RANK:50 )
在线值:
发帖
7
回帖
102
粉丝
0
zysyyz 活跃值 1 2010-7-30 17:24
3
0
本想潜水一下。。。。但看到如此好贴——不顶不行啊!!!
microdebug
雪    币: 336
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:280 )
在线值:
发帖
23
回帖
212
粉丝
0
microdebug 活跃值 6 2010-7-30 21:37
4
0
谢谢,分享快乐
yzwyq
雪    币: 463
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
14
回帖
118
粉丝
0
yzwyq 活跃值 2010-7-30 22:13
5
0
好啊,谢谢了啊
HighHand
雪    币: 1926
活跃值: 活跃值 (27)
能力值: ( LV12,RANK:530 )
在线值:
发帖
32
回帖
112
粉丝
4
HighHand 活跃值 11 2010-7-30 22:17
6
0
好帖,得顶。
Ptero
雪    币: 390
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:330 )
在线值:
发帖
18
回帖
163
粉丝
0
Ptero 活跃值 8 2010-7-30 22:52
7
0
native的木马岂不是很可怕,比如纪录windows登录密码
microdebug
雪    币: 336
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:280 )
在线值:
发帖
23
回帖
212
粉丝
0
microdebug 活跃值 6 2010-7-30 23:20
8
0
native 程序必须要利用注册表项才能注册启动,安全软件只要监控这一项就可以了;另外,native程序启动的时候,如果不利用bootvid显示画图的话,会自动的切换到VGA的16色蓝屏模式下,很容易被发觉~~
太粗糙了
雪    币: 216
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
5
回帖
11
粉丝
0
太粗糙了 活跃值 2010-7-31 10:01
9
0
谢谢分享,之前不知道,,下了你的附件文件翻译了下
ENVIRONMENT_INFORMATION        STRUCT
  Unknown        DD 21 DUP (?)
  CommandLine     UNICODE_STRING<>
  ImageFile        UNICODE_STRING <>
ENVIRONMENT_INFORMATION ENDS

PSTARTUP_ARGUMENT        STRUCT
  Unknown        DD 3 DUP (?)
  Environment        ENVIRONMENT_INFORMATION <>
PSTARTUP_ARGUMENT ENDS
.const
CCOUNTED_UNICODE_STRING "123456789101234567891012345678910", g_pTxt, 4
.code
start:
NtProcessStartup proc Argument:PSTARTUP_ARGUMENT

        invoke NtDisplayString,addr g_pTxt
        invoke NtTerminateProcess,NtCurrentProcess,0
ret
NtProcessStartup endp
kagayaki
雪    币: 308
活跃值: 活跃值 (31)
能力值: ( LV3,RANK:20 )
在线值:
发帖
164
回帖
1081
粉丝
0
kagayaki 活跃值 2010-10-2 04:45
10
0
收藏!!!!
拍拖
雪    币: 1817
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
22
回帖
187
粉丝
0
拍拖 活跃值 2 2010-10-3 14:16
11
0
楼主,想问下。好像VISTA和WIN7都不可以用了吧?
一个穷光蛋
雪    币: 199
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
87
粉丝
0
一个穷光蛋 活跃值 2010-10-6 11:38
12
0
吸收精华,成长菜鸟.
ahaisoft
雪    币: 206
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
18
回帖
67
粉丝
0
ahaisoft 活跃值 2010-10-7 21:21
13
0
确是好文,解了我心中一个疑问。
loudy
雪    币: 1415
活跃值: 活跃值 (30)
能力值: ( LV9,RANK:480 )
在线值:
发帖
42
回帖
204
粉丝
0
loudy 活跃值 10 2010-10-10 13:04
14
0
强烈支持啊,感谢楼主,好贴
雪妖
雪    币: 266
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
4
回帖
168
粉丝
0
雪妖 活跃值 2010-11-11 15:02
15
0
坚持了5天还是没看 干脆mark一下吧
microdebug
雪    币: 336
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:280 )
在线值:
发帖
23
回帖
212
粉丝
0
microdebug 活跃值 6 2010-11-11 18:18
16
0
当然可以用;
前一阵子开发的项目,native app部分就是支持WIN7,VISTA的,并且支持64位
cnfixit
雪    币: 109
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
90
粉丝
0
cnfixit 活跃值 2010-11-17 11:51
17
0
越看越心惊,越看心越凉,不会的太多了……
shanan
雪    币: 31
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
15
粉丝
0
shanan 活跃值 2010-11-18 09:10
18
0
一定要学习。。。。
jgaoabc
雪    币: 350
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
9
回帖
58
粉丝
0
jgaoabc 活跃值 1 2010-11-18 09:53
19
0
瑞星杀毒软件安装之后在system32目录下生成一个bsmain.exe,应该属于Native app吧,输入表就NTDLL.DLL一个,但为什么用OD无法打开。
9571
雪    币: 115
活跃值: 活跃值 (17)
能力值: ( LV3,RANK:30 )
在线值:
发帖
33
回帖
173
粉丝
0
9571 活跃值 2011-3-11 20:06
20
0
感谢分享这么好的文章
wwwkx
雪    币: 49
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
4
回帖
28
粉丝
0
wwwkx 活跃值 2011-3-20 22:31
21
0
一个全新的领域,让我开了眼界了。
fresharp
雪    币: 51
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
2
回帖
31
粉丝
0
fresharp 活跃值 2011-8-31 15:49
22
0
这种方法还是有一定用处的。就是深入的人很少
yisil
雪    币: 27
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
2
回帖
18
粉丝
0
yisil 活跃值 2011-9-1 09:11
23
0
请问楼主 NDK 哪里可以下载
jerksson
雪    币: 216
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
10
粉丝
0
jerksson 活跃值 2011-9-22 08:04
24
0
下来看看   谢谢LS
zhssln
雪    币: 35
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
12
粉丝
0
zhssln 活跃值 2011-12-12 13:11
25
0
micro,很善于总结。学习下。
lionxyes
雪    币: 877
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
11
回帖
70
粉丝
0
lionxyes 活跃值 2 2011-12-12 15:36
26
0
花了几分钟看了一下,写的不错,简单易懂,感谢楼主
cgfxiaohai
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
10
粉丝
0
cgfxiaohai 活跃值 2011-12-13 15:09
27
0
谢谢!不错的文章,入门很好!
才情岁月
雪    币: 105
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
2
回帖
54
粉丝
0
才情岁月 活跃值 2011-12-15 12:52
28
0
学习了,谢谢!
ddlddy
雪    币: 178
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
9
回帖
84
粉丝
0
ddlddy 活跃值 2012-2-1 17:08
29
0
那么如何用bootvid显示画图呢?
crazybug
雪    币: 6
活跃值: 活跃值 (17)
能力值: ( LV6,RANK:90 )
在线值:
发帖
14
回帖
111
粉丝
0
crazybug 活跃值 2 2012-2-2 12:16
30
0
补充个 支持键盘输入的~
http://www.softrce.net/archives/63
watchsky
雪    币: 2617
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
9
回帖
42
粉丝
0
watchsky 活跃值 2012-2-2 14:26
31
0
传说中入口函数的参数是用注册表传进去吗
yatere
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
6
粉丝
0
yatere 活跃值 2012-2-4 19:19
32
0
确实是资料少,感谢楼主的分享。
最近在看寒江独钓系列的书,深感焦虑啊
游客
登录 | 注册 方可回帖
返回