Native Application 開發詳解(直接在程序中調用 ntdll.dll 中的 Native API,有內存小、速度快、安全、API豐富等8大優勢)

文章目錄:html

                 

1. 引子:算法

2. Native Application Demo 展現:windows

3. Native Application 簡介:api

4. Native Application 有何妙用:安全

5. MJ0011 關於 Native Application 的文章整理:數據結構

6. 互聯網上其餘關於 Native Application 的文章整理:併發

7. 小結:app

                

1. 引子:less

                         

其實在很久之前就看了 MJ0011 翻譯的那個《Native 應用程序詳細》系列的文章,ide

(PS: MJ0011 爲 360 的首席技術執行官,技術是沒的說,不過貌似有點狂妄之說 ~ )

並且看完後對這一系列文章也很感興趣的,因此又去 Google 上找了幾個小資料學習了一下,

而這篇文章呢,則是將我前陣子的所謂的學習給總結出來也順道給大夥分享一下。

雖然這裏是說的總結 Native Application,但最先出現 Native Application 應該是 06 年的事了,

(固然,Native Application 這個技術是一直存在的,只是在 06 年後有了下面這篇文章後就稍微火了點)

其是 Sysinternals 上的一篇由 Mark Russinovich 發表的文章《Inside Native Applications》

文章地址以下:http://technet.microsoft.com/en-us/sysinternals/bb897447

而我卻在 2011 年才得以來總結這個技術,因此我確是屬於研究這些東西的落後者啊 ~

下面我給出一副截圖來看一下 Windows 操做系統下的程序的類型:

image

            

在 Windows 最初設計的時候考慮到了兼容各類系統的應用程序,因此有了環境子系統之說,

其中一開始的時候考慮到了子系統,POSIX 子系統和 OS/2 子系統,

可是隨着歷史的發展,如今也就剩下個 Windows 子系統了,

咱們平常使用的 Windows 操做系統的上層其實也就是指的這個 Windows 子系統了,

至於這裏爲什麼要扯到 Windows 子系統的話,就看下文介紹了。

不少朋友都知道有 Windows 應用程序和 Windows 內核驅動程序之說,

卻不多有知道在 Windows 中還有 Native Application 一說了,

可是這類程序確實是存在的 ~只不過這類程序應用比較窄,也沒有被很好的推廣開來,

固然還有一點就是 Microsoft 天然不但願你隨隨便便的使用 Native API。

           

              

2. Native Application Demo 展現:

              

首先你須要將下載(博文的最後面附上 Demo 的下載地址)的 EXE 文件拷貝一份到 system32 目錄下,

(博文的 Demo 只是拿了網上的代碼而後自行使用 DDK 編譯了而已,Demo 並不是筆者原創)

而後再在註冊表如下路徑中修改 BootExecute,

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

在其中添加 NativeApp_01 Hello World ! 這個字符串,

image

                    

image

          

重啓電腦,而後就能夠看到下面的效果圖了(僅在 XP SP3 上進行了測試)

2011-09-18_111934

              

                   

3. Native Application 簡介:

              

何爲 Native API ?

Native API 就是你 system32 目錄下的那個 ntdll.dll 中所公開的 API(大部分爲 Undocument)~

若是讀者看過我前面的《進程隱藏與進程保護(SSDT Hook 實現)》系列文章的話,

相信確定會知道在 Windows 中 kernel32.dll 中的 API 的調用都會通過轉換,

也就是跳轉到 ntdll.dll 中,而且在 ntdll.dll 中也有與之相對於的 API 調用,

(好比 Kernel32.dll 中的 CreateProcess 在 ntdll.dll 中有 NtCreateProcess 與之對應)

那麼什麼稱之爲 Native 應用程序呢 ?

下面給出一副截圖:

image

            

從上面的截圖能夠看出,在一開始的 Windows NT 內核中是支持三個環境子系統的,

即 POSIX,WINDOWS,OS/2,這些子系統屬於同一層,它們共用了 Windows NT 所提供的 API,

即每個子系統中的 API 的調用都會轉換到下一層的相同調用上,

在 Windows 環境子系統(有 Windows,Posix,OS/2)中的程序,

都會調用其相對於的子系統下的 API,好比 Windows 子系統中的程序有可能會調用 Win32 API CreateProcess,

而 Posix 子系統中的程序也有可能會調用 Posix API CreateProcess(固然有可能在 POSIX 下建立進程不是這個名稱),

可是終歸來講,這兩個 CreateProcess 的調用都會轉換到 Ntdll.dll 中的 NtCreateProcess 中,

也就是上面的三個子系統最後的調用都會迴歸到 ntdll.dll 上,

而咱們的 Native Application 則是繞過 Windows 子系統,

直接本身調用 Native API,好比建立進程的話,我就再也不經過子系統中的神馬 CreateProcess 來完成了,

而是直接在程序中調用 ntdll.dll 中的 Native API NtCreateProcess 來完成,

而這類程序即稱之爲 Native Application !

           

Native Application 的運行環境:

上面也說了,Native Application 是隻可以訪問 ntdll.dll 中的內容的,

而若是是在子系統下運行一個程序的話,必然會加載其餘的 DLL,

好比在 Windows 子系統下一個 kernel32.dll 是必不可少的吧,

若是 Native Application 可以運行在 Windows 子系統下的話,必然也會加載到 Kernel32.dll,

這樣不就和上面相違背了嘛 ~

總之:Native Application 是不可以運行在任何子系統下的 !

好比在 Windows 子系統下運行 Native Application 會彈出以下錯誤對話框:

image

          

Native Application 的啓動時機:

對於 Windows 操做系統的引導過程,這裏須要帶一筆的,Windows 操做系統啓動時,

當 Windows 內核的引導完成之後,就會啓動會話管理器 smss.exe 進程了,

smss.exe 進程雖然是一個用戶模式的進程,可是這個進程相對於其餘用戶模式進程是具備必定特殊性的,

首先 smss.exe 進程是直接創建在 Windows NT 內核上的,其不依賴於任何一個環境子系統,

至於不依賴於任何一個環境子系統這一說的話,仍是能夠很好的解釋的,

由於當環境子系統進程(Windows 子系統進程爲 csrss.exe)就是由 smss.exe 進程啓動的,

而後 smss.exe 是 Windows 操做系統啓動的第一個用戶態進程,

而 Native Application 也屬於用戶態程序,天然 Native Application 的啓動是在 smss.exe 以後,

然後前面也說過,Native Application 運行時,子系統進程還還沒有啓動,

因此 Native Application 的啓動則是在 csrss.exe 以前的,

而話又說回來,csrss.exe 就是由會話管理器(smss.exe)啓動的,

因此 Native Application 的啓動時機也就只有一種可能了,

即 smss.exe 先啓動 Native Application,而後 Native Application 開始執行,

等到 Native Application 都給執行完了後 smss.exe 再啓動 csrss.exe 進程。

(事實上,Win32 應用程序環境子系統 csrss.exe 本質上也是一個 Native Application ~)

下面給出一副截圖以說明 SMSS.EXE 的在啓動過程當中所完成的工做:

運行啓動時執行的程序便是執行 Native Application

image

          

           

4. Native Application 有何妙用:

              

前面也提到過,Native Application 的應用範圍比較窄,這主要受如下幾點約束:

首先,Native Application 是直接調用 Native API 來完成任務的,

而在 Windows 中,Native API 絕大部分都是 Undocument 的,這樣開發起來天然難度會大不少了。

而後,因爲 Native Application 是調用的 Undocument API,

說不許那一天 Microsoft 就在下一代 Windows 中修改了這個 API,這樣的話,你程序的可移植性也就徹底沒了。

最後的話,Native Application 的執行環境並不是是在 Windows 子系統中,

事實上,當 Native Application 開始執行的時候,Windows 子系統進程(csrss.exe)進程都尚未啓動的 ~

因此 Native Application 的執行是受限制的,其不可以執行子系統中的任何東西,

說白一點的話就是 Native Application 只可以調用 ntdll.dll 中的 API,

其餘 DLL 中的 API 一概不得調用,這樣也就註定 Native Application 的應用範圍不會很普遍了。

          

應用範圍比較窄並不等於說沒有應用價值,

也仍是有蠻多的軟件,包括一些商業軟件也都是用了 Native Application,

下面來看一些 Native Application 的應用(我也只是從網上道聽途說,不過有些也確實是本身也用過的):

最典型的應用天然是屬於 Windows 操做系統自帶的磁盤自檢程序了;

而後比較典型的商業應用是瑞星的開機殺毒,即實現讓病毒在你尚未徹底開機以前死掉;

而後就是能夠經過 Native Application 來實現接管 Windows 的開機啓動界面和密碼輸入界;

還能夠經過 Native Application 來實現開機前的磁盤修復(Windows 自帶了這款工具也是這樣實現的);

      

           

5. MJ0011 關於 Native Application 的文章整理:

          

這一小節裏面主要是整理一下關於 MJ0011 的 Native Application 的博文,

也就是說我這裏純粹是將他的東西給貼出來瞧瞧,關於 MJ0011 博文的原地址爲:

《NATIVE應用程序詳細之一》:

http://hi.baidu.com/mj0011/blog/item/7ee496d67a4d4d2f07088bc7.html

《NATIVE應用程序詳細之2 NATIVE應用程序的優點和劣勢》

http://hi.baidu.com/mj0011/blog/item/f8108f2f5890fb381e30896d.html

《native應用程序詳細之三 構建native應用程序》:

http://hi.baidu.com/mj0011/blog/item/725b4882042b03a20df4d269.html

《深刻Native應用程序》(該文翻譯自《Inside Native Application》):

http://hi.baidu.com/mj0011/blog/item/85c0b50f80b1baedab6457de.html

《native app GUI界面的實現》:

http://hi.baidu.com/mj0011/blog/item/6e5a22fa214c8116a9d3115b.html

                   

Native 應用程序簡介:

NT 系統被設計成爲支持子系統(封裝),它能夠執行在不一樣平臺上的代碼。包括但不限於:POSIX、OS/2和Win32,

爲了管理這些子系統,NT內核輸出了大量名爲 Native API的API函數,子系統服務將這些函數包裝爲他們本身的函數。

例如:CreateFile和fopen都被映射到NtCreateFile.那麼子系統管理程序運行在哪一個子系統中?

爲了不先有雞仍是先有蛋的問題,NT系統一樣支持原生的Native應用程序。

這些Native應用程序是獨立於子系統的。如今,全部的子系統應用程序都須要註冊它們本身的子系統服務,

顯然,Kernel32是一個Win32應用程序,csrss註冊WIN32子系統,而後通知子系統管理器SMSS,

所以,一個Native應用程序是沒法調用其中數千種API的,

同時它也沒法使用一些基本的DLL中的函數例如kernel3二、user3二、gdi32等,

其它任何調用了這三者的DLL中的函數的DLL也沒法被使用。

事實上,加載者在其入口點沒有被加載前,並不容許加載決大多數的Win32 DLL。

所以,native應用程序被限制只許使用一個DLL:ntdll.dll,這個DLL供應全部Native和運行函數。

可是想一想,既然全部Win32函數最後都是去調用Ntdll.dll中的函數來實現的(除了GUI部分),

這些函數就已經足夠了,不是嗎?

           

Native應用程序優點:

(一) 內存使用和大小:由於Native應用程序並不須要加載90多個DLL到內存中去,所以其使用的內存是很小的。

(二) 速度:Native API比Win32對應的函數要更快(一般會快不少),

儘管實際上不少時間都被消耗在Win32 API的封裝上,這些包括修改、兼容性選項,和其餘的代碼部分,

這些都會在執行真正的Native調用前執行。若是你知道如何去作並且但願它運行得更快,Native是一個很好的方法。

由於不須要加載那90多個DLL,kernel32不須要到csrss和smss作lpc註冊,所以啓動也是很是快速和直接的。

(三) 熟悉程度和特性:Native應用程序並無古怪的入口點或者奇怪的Hack,就象讀命令行同樣簡單使用,

而事實上將在後面介紹,Native應用程序和Console程序同樣啓動與_main函數,

經過一組簡單的char*[]隊列來接受命令行參數和環境變量,就象一個典型的Win32 Console程序同樣,

一些特性例如緩衝區溢出保護(/GS)、Safe SEH(/SAFESEH)、hotpathing(/HOTPATCH),

以及其餘的特性都被支持。

(四) 豐富:Native API很是豐富,它們提供的特性和功能性要遠遠超越Win32函數所能達到的程度。

這並非說Win32沒法作到Native API那樣的更困難和更復雜的工做,而是Win32太過簡單而已,

好比Win32函數中,沒法遠程注入一個Section到一個進程中,由於MapViewOfFileEx不提供進程句柄接口,

而Native API則能夠實現這個功能。

(五) 安全:可是Native應用程序有這樣一個特色:人們對於Native API不是十分熟悉,

他們須要花費更多的時間才能理解你的代碼,而更重要的是,沒法使用一個用戶模式的debugger來調試Native應用程序,

只有SoftIce和使用內核模式遠程鏈接的WinDbg才能夠對其進行調試,這足以讓那些廢物腳本小子去死了,

再說一遍,這並不意味着Native 應用程序是「不可調試的,安全的」,只是它更模糊更難被破解。

(六) 同內核模式的鏈接:由於Native應用程序只使用Native API,這些函數在內核模式仍然可用,

這樣,一個Native程序只需少許修改就可修改成內核驅動,而Win32程序則須要幾乎重寫全部代碼。

(七) 運行在獨立於子系統的環境中:由於Native應用程序並不依賴與任何子系統,

它運行於一個正常應用永遠沒法再次獲得的環境中,好比autochk.exe,它運行與任何子系統加載以前,

並負責顯示'press any key to scan your hard disk"信息,並掃描你的硬盤是否有錯誤。

在這個模式運行容許你顯示信息到啓動屏幕上,以及不少加強特性。

(八) 標準性:不象Win32函數有一個正常版本,一個"Ex"版本,以及常常有一個"擴展其餘功能"的版本,

以及常常返回0,1,-1或一些隨機的數值來表示成功,而且要使用SetLastError來設置返回錯誤,

在Native應用程序中,這些垃圾都是不存在的,全部的Native API都有統一的標準,

全部都返回NTSTAUS(除非明確表示會返回一個特定的值),NTSTAUS是一個標準的錯誤碼定義,

並且使用它們時你也不須要考慮該死的Ex版本。

             

Native 應用程序劣勢:

(一) 和Win32開發的差別較大:若是你之前歷來沒有進行過Native API或內核驅動的相關開發,

你可能須要學習全部的API相關知識,固然,他們的名字是類似的,可是他們的標誌常常是徹底不一樣的,

並且他們的返回值,極可能使你感到迷惑。

(二) 缺乏文檔:雖然全部的Rtl*函數都是有文檔的,數百個其餘的Native API還是無文檔的。

(三) 缺乏商業價值:雖然Native程序如此美好,可是建議你不要在商業產品中使用 Native API 或着使用Native應用程序,

Native API是可能改變的,雖然它們一般沒有改變,可是他們極可能變得再也不有用,不要拿你的客戶的錢冒險。

(四) 沒有GUI、及輸入/輸出接口:沒有"Native控制檯程序",你沒法簡單地從用戶那裏接受到輸入或顯示些什麼到屏幕上,

由於那些接口都沒法再使用(控制檯API都是Win32 API)。

         

Native 應用程序構建:

你須要這二者或二者之一來建立你的 native 應用程序:

(1)Visual C++ 2005 Express(or higher)

(2)Windows Driver Kit

咱們將從基礎開始,首先你須要建立你的應用程序的頭文件,precomp.h,ntddk.h

   1:  #include "ntddk.h"

Now that that's done, create your main initialization file,

which we will call init.c. In this file, add precomp.h like this:

   1:  #include "precomp.h"

And define your entrypoint:

 

   1:  NTSTATUS __cdeclmain(
   2:   
   3:  INT argc,
   4:   
   5:  PCHAR argv[],
   6:   
   7:  PCHAR envp[],
   8:   
   9:  ULONG DebugFlag OPTIONAL)
  10:   
  11:  {
  12:   
  13:  // Entry code here
  14:   
  15:  }

Hopefully you are familiar with this entrypoint, it's the typical one used by C programs,

except with an addon: the "DebugFlag". Right now, we don't need to care about this.

We'll keep this entry simple, and turn this into a "Hello World":

 

   1:  NTSTATUS __cdecl main(
   2:   
   3:  INT argc,
   4:   
   5:  PCHAR argv[],
   6:   
   7:  PCHAR envp[],
   8:   
   9:  ULONG DebugFlag OPTIONAL)
  10:   
  11:  {
  12:   
  13:  UNICODE_STRING HelloMsg = RTL_CONSTANT_STRING(L"Hello World!\n");
  14:   
  15:  //Say hello
  16:   
  17:  NtDisplayString(&HelloMsg);
  18:   
  19:  }
  20:   

Now, if you're wondering what NTSTATUS is,

what NtDisplayString is or what

RTL_CONSTANT_STRING and UNICODE_STRINGs are,

then you'll need to read all the DDK documentation you can swallow,

as well as Nebett's Undocumented Native API book.

Although it's outdated, the information about the APIs is still pretty valid.

I also plan to possibly give a fully-fledged lesson on this if lots of

people are interested.So now that we have our simple program, we need to build it.

I prefer using the WDK myself,

because it's much simpler and doesn't require changing 100 of MSVC's default settings.

Assuming you've properly installed the WDK and entered the Windows build environment for

your OS (from the Start Menu),

you'll need to create two files in the directory where init.c and precomp.h are:

sources and makefile.

Sources should look something like this:

--

 

   1:  TARGETNAME=native
   2:   
   3:  TARGETTYPE=PROGRAM
   4:   
   5:  UMTYPE=nt
   6:   
   7:  INCLUDES=\
   8:   
   9:  $(DDK_INC_PATH); \
  10:   
  11:  $(NDK_INC_PATH);
  12:   
  13:  SOURCES=init.c
  14:   
  15:  PRECOMPILED_INCLUDE=precomp.h
  16:   

--

that you'll have to set NDK_INC_PATH as an environment variable yourself,

to where the NDK is installed (DDK_INC_PATH is already setup by the WDK).

Finally, you'll need a makefile:

--

   1:  INCLUDE $(NTMAKEENV)\makefile.def

--

That's all you really need for our purposes.

So now you should have init.c, precomp.h, sources and makefile.

The only thing left is to write "build",

and the WDK should do the magic and create your first native application.

Unforunately, you can't really test it for now,

unless you do the following:Open registry editor and browse to

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

Edit the "BootExecute" key and write "native" instead of what's currently in it,

then copy native.exe to your system32 directory and restart the computer.

You should see the message appear on the screen for a little while.

Make sure that you do NOT boot with /NOGUIBOOT, or else you will never see it.

      

//////////////////////////////////////////////////////////////////////////////  

//////////////////////////////////////////////////////////////////////////////  

/////////////////MJ0011 翻譯《Inside Native Application》//////////////////////

//////////////////////////////////////////////////////////////////////////////  

//////////////////////////////////////////////////////////////////////////////  

           

導言

若是你對Windows Nt結構有必定的瞭解,你可能會知道,Win32 應用程序所使用的API,

並不是是"真正"的NT API,POSIX、OS/2和Win32這些Windows NT 操做系統環境,

使用他們本身的 API 同他們的客戶應用程序進行交流,但卻使用Windows NT的"Native" API同Windows NT交流,

這些Native API大都是未公開UnDocumented 的。

大約只有25個API(包含250種功能)在Windows NT設備驅動開發工具包(DDK)裏有所描述。

儘管絕大多數人都不知道,但"Native"應用程序的確存在與Windows NT上,他們在操做環境上沒有任何客戶程序,

這些程序交流着Native NT API而且不能使用任何操做環境API好比 Win32,爲何這樣一種程序是必須的呢?

由於在Win32子系統啓動以前(大約在登錄對話框出現時)只能夠運行Native應用程序,

最多見的Native應用程序的例子是"autochk"程序,他在初始化藍色登錄屏幕前運行chkdsk(程序在屏幕上打印一串".")。

固然,Win32應用程序環境服務程序:CSRSS.exe(客戶-服務運行時間子系統),也是一個Native應用程序。

在這篇文章裏,我將會講述如何構造一個Native應用程序以及它們是如何工做的,

同時我也會提供一個Native應用程序的示例源代碼。

這個示例很容易安裝,它會在啓動時的藍色屏幕打印一段你指定的字符串。

               

Autochk是如何被執行的

Autochk在當內存分頁被打開,Windows啓動和系統開始驅動被載入之間的時間內運行,

在這個時間點會啓動會話管理器(smss.exe)進入Windows NT用戶模式,而且沒有任何程序被啓動。

註冊表中:HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute

一個MULTI_SZ類型的鍵值,這裏存放着將被會話管理器所執行的程序名稱和參數,一般是Autochk後加*號做爲其參數

Autocheck Autochk * 
;名稱 程序名 參數

會話管理器在<winnt>\system32目錄下查找該值列出的可執行程序,當Autochk運行時,沒有任何文件被打開,

因此Autochk能夠用raw模式打開任何一個驅動器卷(包括根驅動器),並操做其磁盤數據結構,

以後的任什麼時候間點都沒法進行相似這樣的操做。

              

編譯Native應用程序

1. 微軟沒有提供相應的文檔,可是NT DDK構建器知道如何去生成一個Native應用程序,

並且它能夠被用來編譯autochk程序,和編寫設備驅動程序同樣,你必須指定SOURCE文件中的信息來定義應用程序,

然而和編寫驅動不一樣的時,你在SOURCE文件中要求生成一個Native應用程序須要這樣定義:

TARGETTYPE=PROGRAM

2. 構建器使用一個標準的makefile來進行嚮導:\ddk\inc\makefile.def 在編譯Native應用程序時,

會查找名爲nt.lib的運行庫。不幸的是,微軟並沒在DDK上裝載這個文件(在Windows Server 2003 DDK裏包括了這個文件,

可是我懷疑你用這個版原本鏈接你的Native應用程序是沒法運行在Windows XP或Windows 2000上的)無論怎樣,

你能夠忽略這個錯誤,方法是加入一行不考慮nt.lib,而指定Visual C++ 的運行庫msvcrt.lib到makefile.lib中。

3. 若是你在DDK的"Checked Build"環境下進行編譯,

將會在%BASEDIR%\lib\%CPU%\ Checked(例如c:\ddk\lib\i386\checked\ native.exe)

產生一個包含了所有調試信息的Native應用程序。

4. 若是在"Free Build"環境中編譯,你會在%BASEDIR%\lib\%CPU%\Free獲得一個釋出版本的程序,

這些和構造設備驅動程序放置的位置是同樣的。

5. Native應用程序有着".exe"的擴展名,可是你不能像 Win32的.exe文件那樣去運行它,

若是你在Win32環境下運行下,將會獲得以下提示:"<應用程序名> 應用程序沒法在Win32模式中運行。"

             

深刻學習Native應用程序

1. Native應用程序的入口點是NtProcessStartup,相似WinMain或Main,不一樣於其餘的 Win32入口點的是,

Native應用程序提供一個數據結構來存放它的惟一的參數來定位命令行參數。

2. 大多數的Native應用程序的運行環境是由Windows Nt的Native API輸出庫 - NTDLL.DLL提供的。

3. Native應用程序必須使用RtlCreateHeap(一個ntdll函數)來建立他們本身的堆來分配存儲,

使用RtlAllocateHeap來分配內存以及用RtlFreeHeap來釋放內存。

4. Native應用程序須要使用NtDisplayString 函數才能夠打印想要的內容到屏幕上(將被輸出到初始化時的藍色屏幕上)。

5. Native應用程序不像Win32程序那樣簡單地從他們的啓動函數返回,你須要調用NtProcessTerminate函數來結束它的進程。

6. NTDLL運行包含了數百個函數容許Native應用程序執行文件I/O,與設備驅動進行相連,並執行進程間通信。

不幸的是,他們大部分都是未公開的。

         

Native應用程序實例

1. 我建立一個Native應用程序用來演示Native應用程序是如何構建的以及他們是如何工做的。

運行install.bat來安裝Native程序。

2. 批處理程序複製Native.exe到你的<winnt>\system32目錄,

並在註冊表中增長一個BootExecute的入口點: native Hello World!

3. 當你從新啓動時,會話管理器運行完autochk後就會執行Native,Native分配一些堆,

定位它的命令行參數並打印參數("Hello world!")到藍色屏幕上,它所使用的函數上面已說過了。

若是你想要打印其餘的簡單內容,能夠編輯BootExecute值使用regedit或regedit32,

修改"Hello world"爲你想要的信息。

4. 運行uinstall.bat能夠卸載這個Native執行程序。它從<winnt>\system32 目錄刪除 Native.exe,

並修改BootExecute值爲一般的值。

5. 若是你想要構建native程序你必需要用Windows設備驅動工具包(DDK),

複製makefile.def到 \ddk\inc而後你能夠運行構建。

        

Native.H

   1:  //Environment information, which includes command line and image file name
   2:  typedef struct 
   3:  {
   4:      ULONG            Unknown[21];     
   5:      UNICODE_STRING   CommandLine;
   6:      UNICODE_STRING   ImageFile;
   7:  } ENVIRONMENT_INFORMATION, *PENVIRONMENT_INFORMATION;
   8:   
   9:  // This structure is passed as NtProcessStartup's parameter
  10:  typedef struct 
  11:  {
  12:      ULONG                     Unknown[3];
  13:      PENVIRONMENT_INFORMATION  Environment;
  14:  } STARTUP_ARGUMENT, *PSTARTUP_ARGUMENT;
  15:   
  16:  // Data structure for heap definition. 
  17:  // This includes various sizing parameters and callback routines, 
  18:  // which, if left NULL, result in default behavior
  19:  typedef struct 
  20:  {
  21:      ULONG     Length;
  22:      ULONG     Unknown[11];
  23:  } RTL_HEAP_DEFINITION, *PRTL_HEAP_DEFINITION;
  24:   
  25:  // Native NT api function to write something to the boot-time
  26:  // blue screen
  27:  NTSTATUS NTAPI NtDisplayString(
  28:      PUNICODE_STRING String
  29:      );
  30:   
  31:  // Native applications must kill themselves when done - 
  32:  // the job of this native API
  33:  NTSTATUS NTAPI NtTerminateProcess(
  34:      HANDLE ProcessHandle, 
  35:      LONG ExitStatus 
  36:      );
  37:   
  38:  // Definition to represent current process
  39:  #define NtCurrentProcess() ( (HANDLE) -1 )
  40:   
  41:  // Heap creation routine
  42:  HANDLE NTAPI RtlCreateHeap(
  43:      ULONG Flags, 
  44:      PVOID BaseAddress, 
  45:      ULONG SizeToReserve, 
  46:      ULONG SizeToCommit, 
  47:      PVOID Unknown,
  48:      PRTL_HEAP_DEFINITION Definition
  49:      );
  50:   
  51:  // Heap allocation function (ala "malloc")
  52:  PVOID NTAPI RtlAllocateHeap(
  53:      HANDLE Heap, 
  54:      ULONG Flags, 
  55:      ULONG Size 
  56:      );
  57:   
  58:  // Heap free function (ala "free")
  59:  BOOLEAN NTAPI RtlFreeHeap(
  60:      HANDLE Heap, 
  61:      ULONG Flags, 
  62:      PVOID Address 
  63:      );

       

Native.C

   1:  //======================================================================
   2:  //
   3:  // This is a demonstration of a Native NT program. These programs
   4:  // run outside of the Win32 environment and must rely on the raw
   5:  // services provided by NTDLL.DLL. AUTOCHK (the program that executes
   6:  // a chkdsk activity during the system boot) is an example of a
   7:  // native NT application.
   8:  //
   9:  // This example is a native 'hello world' program. When installed with
  10:  // the regedit file associated with it, you will see it print 
  11:  // "hello world" on the initialization blue screen during the system
  12:  // boot. This program cannot be run from inside the Win32 environment.
  13:  //
  14:  //======================================================================
  15:  #include "ntddk.h"
  16:  #include "stdio.h"
  17:  #include "native.h"
  18:   
  19:  // Our heap
  20:  HANDLE Heap;
  21:  //----------------------------------------------------------------------
  22:  // NtProcessStartup
  23:  // Instead of a 'main', NT applications are entered via this entry point. 
  24:  //----------------------------------------------------------------------
  25:  void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
  26:  {
  27:      PUNICODE_STRING commandLine;
  28:      PWCHAR stringBuffer;
  29:      PWCHAR argPtr;
  30:      UNICODE_STRING helloWorld;
  31:      RTL_HEAP_DEFINITION  heapParams;
  32:      
  33:      // Initialize some heap
  34:      memset( &heapParams, 0, sizeof( RTL_HEAP_DEFINITION ));
  35:      heapParams.Length = sizeof( RTL_HEAP_DEFINITION );
  36:      Heap = RtlCreateHeap( 2, 0, 0x100000, 0x1000, 0, &heapParams );
  37:      
  38:      // Point at command line
  39:      commandLine = &Argument->Environment->CommandLine;
  40:      // Locate the argument
  41:      argPtr = commandLine->Buffer;
  42:      while( *argPtr != L' ' )
  43:      {
  44:          argPtr++;
  45:      }
  46:      argPtr++;
  47:      
  48:      // Print out the argument
  49:      stringBuffer = RtlAllocateHeap( Heap, 0, 256 );
  50:      swprintf( stringBuffer, L"\n%s", argPtr );
  51:   
  52:      helloWorld.Buffer = stringBuffer;
  53:      helloWorld.Length = wcslen( stringBuffer ) * sizeof(WCHAR);
  54:      helloWorld.MaximumLength = helloWorld.Length + sizeof(WCHAR);
  55:   
  56:      NtDisplayString( &helloWorld );
  57:      
  58:      // Free heap
  59:      RtlFreeHeap( Heap, 0, stringBuffer );
  60:   
  61:      // Terminate
  62:      NtTerminateProcess( NtCurrentProcess(), 0 );
  63:  }

                         

Install.bat:

   1:  @echo off
   2:  copy native.exe %systemroot%\system32\.
   3:  regedit /s add.reg
   4:  echo Native Example Installed

              

UnInstall.bat:

   1:  @echo off
   2:  del %systemroot%\system32\native.exe
   3:  regedit /s remove.reg
   4:  echo Native Example Uninstalled

           

           

6. 互聯網上其餘關於 Native Application 的文章整理:

         

下面給出的則是我在互聯網上其餘地方找到的關於 Native Application 的比較好的資料,

這裏也只是將這些資料進行一個整理。

《native app 開發小結(一)》:

http://hi.baidu.com/316526334/blog/item/32823e8a83d87b1fc9fc7a0f.html

《native app 開發小結(二)》:

http://hi.baidu.com/316526334/blog/item/43a21061ad619cd28cb10d08.html

《Native Application 應用之開機殺毒》:

http://www.cublog.cn/u/8754/showart_447592.html

             

程序類型

關於程序級別的分類,大概能夠分爲三層:應用層程序,即普通的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,形如:

   1:  void NtProcessStartup( PSTARTUP_ARGUMENT Argument )

其中,參數PSTARTUP_ARGUMENT是一個結構體,用來存放傳入參數。

程序退出時,主動調用函數NtProcessTerminate退出,它不會像普通應用程序同樣一個返回return就退出了。

基本的結構就是這樣了:

 

   1:  void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
   2:   
   3:  {
   4:   
   5:  // do something else
   6:   
   7:  NtProcessTerminate( NtCurrentProcess(), 0 );
   8:   
   9:  }
  10:   

固然如今尚未包含頭文件之類的。

                             

開發語言及第三方的庫

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 的重載。

使用堆函數過程以下:首先建立一個全局堆,而後在這個全局堆上分配和釋放局部堆。

 

   1:  HANDLE hGlobalHeap = NULL; // for globle call
   2:   
   3:  void* __cdecl operator new(size_t size)
   4:   
   5:  {
   6:          if(hGlobalHeap == NULL)
   7:               return NULL;
   8:          return RtlAllocateHeap(hGlobalHeap,0/*HEAP_ZERO_MEMORY*/,size);
   9:  }
  10:   
  11:  void __cdecl operator delete(void* addr)
  12:   
  13:  {
  14:          if(hGlobalHeap && addr) (void)RtlFreeHeap(hGlobalHeap,0,addr);
  15:  }
  16:   

          

關於 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模板,如:

 

   1:  TARGETNAME=defrag
   2:   
   3:  TARGETPATH=obj
   4:   
   5:  TARGETTYPE=PROGRAM
   6:   
   7:  INCLUDES=$(PUBLIC_ROOT)\inc\ddk
   8:   
   9:  SOURCES=defrag.cpp
  10:   

注意:上面說的DLL的編譯環境和native app的編譯環境要一致,

指的是不要用WDK編譯的native去嘗試連接VS編譯的DLL,反之亦然。

   1:  //NTSTATUS NTAPI NtDisplayString( PUNICODE_STRING String);
 

Native GUI               

在native app執行環境下畫界面是不可行的,可是不是說作不到。

前面說了,能夠寫一個native app來接管windows的啓動界面和密碼輸入界面,那麼這個界面是如何畫的呢?

也有從驅動裏實現的。可是,事實上,MS提供了一個native級別的動態庫,名爲:Bootvid.dll,

用來實現GUI啓動屏幕的引導視頻驅動,這個dll導出了一些函數,能夠實現畫圖,貼圖功能,

固然,這些函數接口仍然是未公開的。呵呵~

另外,在native app程序,能夠利用一個函數向屏幕打印輸出字符串,名爲:

可是,事實上,這個函數已經不推薦使用了,

在用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下操做文件,考慮的狀況是比較單一的,不會擔憂文件或目錄被鎖,

從而出現不能訪問的狀況,也不會考慮過多的併發問題。

因此,功能會更加集中,運行效率會更高,操做的空間和權限也更大。

僅限於此,就到這吧 ~

           

        

7. 小結:

          

上面的文字呢就大致的把 Native Application 給介紹的差很少了,

主要是總結了一下本身關於 Native Application 的理解,

而後再將 MJ0011 和互聯網上的幾位博主的文章給整理了一下(原博文排版不怎麼好),

這裏對 MJ0011 以及所整理的文章的博主表示感謝 ~

博文中的 Demo 我是採用的 DDK 2600.1106 編譯的,至於 WDK 7 的話,我沒有去試哦 ~

有興趣的能夠直接下載了 Demo 進行測試的,代碼什麼的都在裏面,

source 和 makefile 我也都整理好了放在 Demo 中 ~

       

最後仍是和以往同樣,給出些我近來的一些疑問:

我曾經從一臺電腦 A 上下載了卡巴斯基的試用版,而後我將這個試用版的安裝文件拷貝到了電腦 B 上,

這時我發現卡巴斯基的這個安裝文件在電腦 B 上是沒法運行的 ~ 直接報錯,

固然,這個安裝文件在電腦 A 上是能夠運行安裝的,

我想應該是卡巴斯基的這個安裝文件在拷貝的過程當中仍是下載的過程當中記錄下了個人電腦 A,

而後在安裝的時候,其自動判斷是不是在電腦 A 上安裝運行,

若是是的話,則能夠成功安裝,若是不是,則直接報錯 ~

我想知道上面是怎麼來實現的呢 ? 我只是下載和拷貝了一下哦 ~

                

還有就是貌似要考個微軟的 MCTS 證書,

應該是 Windows 方向的 71-511 或者 Web 方向的 71-515 這兩門考試,

不曉得大夥有什麼好建議或者好的資料沒有哦 ~ 能否提供一些呢 ~ 謝謝咯 ~

    

而後再問一下哦,有沒有湖南婁底的啊 ? 國慶組隊回去否 ?(我在深圳 ~)

            

下載 Demo Source Code

           

版權全部,迎轉載,但轉載請註明: 轉載自  Zachary.XiaoZhen - 夢想的天空

http://www.cnblogs.com/BoyXiao/archive/2011/09/21/2183059.html

相關文章
相關標籤/搜索