native app開發(fā)小結(jié)
作 者: microdebug
時(shí) 間: 2010-07-30,15:12:48
鏈 接: http://bbs.pediy.com/showthread.php?t=117694
沒什么技術(shù)含量,開發(fā)小結(jié)而已。
Native app 程序開發(fā)
By microDebug
程序類型關(guān)于程序級(jí)別的分類,大概可以分為三層:
應(yīng)用層程序,即普通的APP程序;
Native App程序,如常見的chkdsk工具,PQ分區(qū)工具等,都屬于這類,它是在win子系統(tǒng)未啟動(dòng)起來就執(zhí)行的程序,執(zhí)行環(huán)境比較純凈,只能調(diào)用ntdll.dll導(dǎo)出的函數(shù);
Driver 內(nèi)核驅(qū)動(dòng)程序,因功能不同也分為若干類,如設(shè)備驅(qū)動(dòng)程序,內(nèi)核擴(kuò)展程序,文件系統(tǒng)驅(qū)動(dòng),過濾驅(qū)動(dòng)等,同屬于內(nèi)核態(tài)程序;
其中,native app在項(xiàng)目開發(fā)中用的較少,所用的函數(shù)接口MS也均未公開,開發(fā)難度和驅(qū)動(dòng)相當(dāng),所以很少有人問津。但是,事實(shí)上,在某些應(yīng)用場(chǎng)景下,用native app來實(shí)現(xiàn)是非常完美的,比如:接管winodws的開機(jī)啟動(dòng)界面和密碼輸入界面,需要native app;在開機(jī)前,執(zhí)行磁盤修復(fù),需要native app;開機(jī)前,執(zhí)行殺毒,或者磁盤整理,因?yàn)榇藭r(shí)環(huán)境比較純凈,需要native app。諸如此類~
最近,開發(fā)一個(gè)Native App項(xiàng)目,其規(guī)模和復(fù)雜度也不一般。期間遇到很多問題,在逐一解決的時(shí)候也收獲了很多東西?,F(xiàn)在略作整理,以備將來查用,二來與大家分享之~
Native app 基本工作原理這里,只想簡(jiǎn)單的描述下。
Windows的設(shè)計(jì)是基于分層模型的,在設(shè)計(jì)之初,內(nèi)核NT支持三個(gè)子系統(tǒng),OS/2,posix,win32,這些子系統(tǒng)同屬于一個(gè)層面上,它們公用windows nt提供的系統(tǒng)API和例程。其中,在某一個(gè)子系統(tǒng)上的API調(diào)用,都會(huì)經(jīng)過NT”native”API同windowsNT進(jìn)行通信。這些native API就是ntdll.dll導(dǎo)出的函數(shù),因?yàn)樗鼘?dǎo)出的大部分函數(shù)都只是起一個(gè)從子系統(tǒng)到NT內(nèi)核的轉(zhuǎn)發(fā)傳遞作用,所以也成為stub函數(shù),這些函數(shù)的原型大多是未公開的,在早期的DDK里會(huì)有相關(guān)的描述,但是現(xiàn)在沒了,取而代之的是內(nèi)核實(shí)現(xiàn)的zw*,nt*開頭的驅(qū)動(dòng)函數(shù)。這里表明了MS的一個(gè)態(tài)度,不希望第三方在native app上干涉windows的太多工作,比如,接管了開機(jī)啟動(dòng)系統(tǒng),接管了登錄密碼界面:D. 后來,因?yàn)榉N種歷史原因,對(duì)OS/2和posix子系統(tǒng)的支持逐漸被淡忘。但是這種分層模型仍然存在,native app就是工作在子系統(tǒng)未啟動(dòng)之前,此時(shí)的系統(tǒng)環(huán)境很純凈,權(quán)限也相對(duì)較高;另外,對(duì)操作系統(tǒng)來說,支持native app也是一種必須,因?yàn)樵谧酉到y(tǒng)啟動(dòng)之前,很多功能的程序只能以native app來呈現(xiàn),比如登錄界面,CSRSS~
具體的啟動(dòng)時(shí)機(jī):
Native app由啟動(dòng)會(huì)話管理器(smss.exe)來啟動(dòng),如果想通知smss來執(zhí)行一個(gè)native app程序,只需要修改一個(gè)注冊(cè)表項(xiàng),smss在每次啟動(dòng)的時(shí)候會(huì)去檢查該項(xiàng),確保該項(xiàng)下面的每個(gè)native app程序依次執(zhí)行。注冊(cè)表項(xiàng)為:HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute ,其類型為MULTI_SZ, 又是MS玩的一種字符串類型—多字符串類型,也就是說,這個(gè)MULTI_SZ字符串包含多個(gè)以\0結(jié)尾的子字符串,而整個(gè)字符串以\0\0結(jié)尾。在該注冊(cè)表項(xiàng)后面添加要注冊(cè)的native 程序名和參數(shù)就可以了。
關(guān)于native app的更多詳細(xì)介紹,可以參考Mark Russinovich的一篇關(guān)于native的文章。
開發(fā)相關(guān)Native app程序結(jié)構(gòu)
Native app程序結(jié)構(gòu)很簡(jiǎn)單,就好像我們寫hello world,需要寫一個(gè)main函數(shù)入口一樣,native app的入口函數(shù)是NtProcessStartup,形如:
void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
其中,參數(shù)PSTARTUP_ARGUMENT是一個(gè)結(jié)構(gòu)體,用來存放傳入?yún)?shù)。
程序退出時(shí),主動(dòng)調(diào)用函數(shù)NtProcessTerminate退出,它不會(huì)像普通應(yīng)用程序一樣一個(gè)返回return就退出了。
基本的結(jié)構(gòu)就是這樣了:
void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
{
// do something else
NtProcessTerminate( NtCurrentProcess(), 0 );
}
當(dāng)然現(xiàn)在還沒有包含頭文件之類的。
開發(fā)語言及第三方的庫(kù)
Native app支持的開發(fā)語言有C/ASM/C++,并且完美的支持C++的類特性,不過要像編寫驅(qū)動(dòng)一樣,需要重載new,delete等內(nèi)存分配函數(shù)。
在內(nèi)存使用上,可以使用兩套接口:堆函數(shù)接口,以及虛擬內(nèi)存函數(shù)接口,但是根據(jù)我的經(jīng)驗(yàn),使用堆函數(shù)接口,更高效并且內(nèi)存bug出現(xiàn)的頻率會(huì)大大降低。舉個(gè)例子:我在調(diào)試native app的時(shí)候,一切正常,且全部通過,但是雙機(jī)調(diào)試的時(shí)候,功能代碼都運(yùn)行完了,在子系統(tǒng)起來的時(shí)候,提示memory_corruption錯(cuò)誤,這個(gè)問題整整找了好幾天都沒有找到,到最后,無意間屏蔽掉了系統(tǒng)的DbgPrint函數(shù),memory錯(cuò)誤才解決。其原因是,native gui圖形模塊的debug消息打印的太快太頻繁,導(dǎo)致調(diào)試緩沖被溢出,當(dāng)屏蔽了系統(tǒng)DbgPrint的時(shí)候,也就是在windbg 下bp DbgPrint,然后a eip,ret后,就正常了。雖然這個(gè)現(xiàn)象和程序無關(guān),但是,用了虛擬內(nèi)存的話,這個(gè)問題會(huì)更加容易重現(xiàn)。關(guān)于這個(gè)問題的重現(xiàn)很容易,就是在native 環(huán)境下雙機(jī)調(diào)試,target機(jī)器一直打印消息,當(dāng)打印到10W條以上時(shí),調(diào)試緩沖就“爆”了。這真不知道是ms的bug,還是自己~~
關(guān)于new,delete的重載。
使用堆函數(shù)過程如下:首先創(chuàng)建一個(gè)全局堆,然后在這個(gè)全局堆上分配和釋放局部堆。
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);
}
關(guān)于NDK:前面說到,native app用的是ntdll.dll的導(dǎo)出函數(shù),而這些函數(shù)MS并沒有公開接口聲明,那么我們使用的時(shí)候,首先必須要自己定義函數(shù)聲明。NDK就是這樣的一個(gè)類庫(kù),它幾乎定義了ntdll.dll導(dǎo)出的全部函數(shù)的聲明以及一些常用的數(shù)據(jù)結(jié)構(gòu)的定義,我們只需要包含相應(yīng)的頭文件,導(dǎo)入ntdll.lib庫(kù),就可以像使用普通的API函數(shù)一樣開發(fā)native app了。
關(guān)于DLL:native app可以調(diào)用同一級(jí)別的DLL,使大型的項(xiàng)目開發(fā)更加容易,更加容易劃分模塊。注意,DLL的編譯環(huán)境要和native app一致。
關(guān)于native app的編譯:可以選擇用vs環(huán)境,也可以用DDK/WDK,但是推薦使用WDK。用VS環(huán)境的話,需要簡(jiǎn)單的設(shè)置下,隨意創(chuàng)建一個(gè)類型的工程,然后修改Linker->system->Native,就可以了。如果用WDK編譯,需要寫一個(gè)SOURCE模板,如:
TARGETNAME=defrag
TARGETPATH=obj
TARGETTYPE=PROGRAM
INCLUDES=$(PUBLIC_ROOT)\inc\ddk
SOURCES=defrag.cpp
注意:上面說的DLL的編譯環(huán)境和native app的編譯環(huán)境要一致,指的是不要用WDK編譯的native去嘗試鏈接VS編譯的DLL,反之亦然。
Native GUI
在native app執(zhí)行環(huán)境下畫界面是不可行的,但是不是說做不到。
前面說了,可以寫一個(gè)native app來接管windows的啟動(dòng)界面和密碼輸入界面,那么這個(gè)界面是如何畫的呢?也有從驅(qū)動(dòng)里實(shí)現(xiàn)的。但是,事實(shí)上,MS提供了一個(gè)native級(jí)別的動(dòng)態(tài)庫(kù),名為:Bootvid.dll,用來實(shí)現(xiàn)GUI啟動(dòng)屏幕的引導(dǎo)視頻驅(qū)動(dòng),這個(gè)dll導(dǎo)出了一些函數(shù),可以實(shí)現(xiàn)畫圖,貼圖功能,當(dāng)然,這些函數(shù)接口仍然是未公開的。呵呵~
另外,在native app程序,可以利用一個(gè)函數(shù)向屏幕打印輸出字符串,名為:
//NTSTATUS
//NTAPI NtDisplayString( PUNICODE_STRING String);
但是,事實(shí)上,這個(gè)函數(shù)已經(jīng)不推薦使用了,在用WDK編譯native app的時(shí)候,會(huì)提示一個(gè)警告信息,deprecated~~
Native app的靈活性
native app由于受到調(diào)用函數(shù)接口未公開,以及開發(fā)難度和調(diào)試難度不小的原因,很少有項(xiàng)目問津,但是,事實(shí)上,它仍然是一種工作于ring3的用戶態(tài)程序,只是在子系統(tǒng)啟動(dòng)之前運(yùn)行,所以,native app程序一般不會(huì)引起系統(tǒng)藍(lán)屏的問題。也正是如此,native 程序工作在一個(gè)相對(duì)純凈的環(huán)境下,可以訪問任何文件,甚至搬移MFT,系統(tǒng)元文件等。
Ntdll.dll為native app導(dǎo)出的函數(shù)雖少,但是可以完成很多的功能。這些導(dǎo)出函數(shù),基本上和內(nèi)核的系統(tǒng)例程都是一一對(duì)應(yīng)的。結(jié)合其他的模塊,driver,應(yīng)用程app,在加之native獨(dú)特的運(yùn)行環(huán)境和執(zhí)行能力,往往會(huì)達(dá)到一個(gè)良好的效果。在這里,僅僅是一個(gè)普及~
具體應(yīng)用及實(shí)例 在開發(fā)native app之前,我想,最好有開發(fā)驅(qū)動(dòng)的基礎(chǔ)。因?yàn)閚ative app程序的編寫規(guī)范基本上和驅(qū)動(dòng)一樣,除了入口函數(shù),調(diào)試方法也一樣,必須要雙機(jī)調(diào)試。當(dāng)然,只是說編寫規(guī)則一樣,驅(qū)動(dòng)特有的函數(shù)例程以及工作原理,二者是毫不相干的。舉個(gè)例子,操作注冊(cè)表,文件IO,線程創(chuàng)建,內(nèi)存使用,二者基本上是一致的,具體的在使用中自己體會(huì)吧。
作為入門例子
作為入門我想還是用Mark Russinovich的例子吧,就好像Hello World的作用一樣,讓你真切的感受下native app程序。該程序在系統(tǒng)啟動(dòng)時(shí),藍(lán)屏界面上輸出一行字符串信息。程序在附件,沒什么過多的需要解釋的。
實(shí)際開發(fā)
實(shí)際開發(fā)中,有不少的應(yīng)用例子。比如,影子系統(tǒng)的啟動(dòng)界面,PQ分區(qū)工具,win系統(tǒng)自帶的chkdsk工具,都屬于這類程序。
下面說下自己的一些經(jīng)歷吧:
項(xiàng)目中有個(gè)需要,對(duì)特定文件進(jìn)行磁盤整理。我們知道,文件系統(tǒng)導(dǎo)出了一組函數(shù)接口,用于對(duì)磁盤上的文件進(jìn)行搬移操作,使文件內(nèi)碎片和外碎片減少,提高IO吞吐率和磁盤訪問率。唯一的限制是,pagefile.sys和日志文件不能整理,其他的文件,如MFT,系統(tǒng)元文件都可以整理。對(duì)于文件整理,更重要的是算法和穩(wěn)定法,當(dāng)然,這是另外一個(gè)話題了。根據(jù)prefreth原理,一個(gè)應(yīng)用程序的工作集頁(yè)面在運(yùn)行時(shí)基本上是趨于穩(wěn)定的,那么這些穩(wěn)定的頁(yè)面如果位于不同的文件(可能是鏈接庫(kù)之類),且這些文件在磁盤上比較分散,那么就會(huì)影響程序的啟動(dòng)時(shí)間了,雖然prefretch做了改善,會(huì)自動(dòng)的激發(fā)系統(tǒng)的磁盤整理來對(duì)“相關(guān)”的文件緊密排放,但仍然是不夠的。所以,關(guān)于這種性能的改善看起來微乎其微,但是做好了,價(jià)值是不可估量的。這僅僅是一個(gè)方面,當(dāng)然,項(xiàng)目中的主要目的并不是這個(gè),雖然也是為了提高性能。
在native app下操作文件,考慮的情況是比較單一的,不會(huì)擔(dān)心文件或目錄被鎖,從而出現(xiàn)不能訪問的情況,也不會(huì)考慮過多的并發(fā)問題。所以,功能會(huì)更加集中,運(yùn)行效率會(huì)更高,操作的空間和權(quán)限也更大。
僅限于此,就到這吧~~
By microdebug
DOC格式粘貼在這里,咋就這么亂?
可參考:http://hi.baidu.com/316526334/blog
native_back.rar下載此附件需要消耗2Kx,下載中會(huì)自動(dòng)扣除。native app.doc下載此附件需要消耗2Kx,下載中會(huì)自動(dòng)扣除。