Native NTApplication本來我是想寫成中文的,但怎么翻譯都覺得不太合適,大多文章都寫作為NativeApplication,并翻譯為原生應(yīng)用程序,或者本地應(yīng)用程序,但自從有了.NET之后,原生應(yīng)用程序好像更多的用作Win32應(yīng)用程序了,本地應(yīng)用程序倒還可以,但怎么聽來也不好聽,算了,還是簡寫作 Native 應(yīng)用程序吧。
Native 應(yīng)用程序與 Win32應(yīng)用程序的文件結(jié)構(gòu)都是 PE 格式的,甚至也是以.exe為后綴名,但是當(dāng)你的 Windows 啟動到一定階段后,正常情況下你卻再也不能運行Native 應(yīng)用程序了,因為此時,Win32子系統(tǒng)已經(jīng)啟動,你已經(jīng)運行到了 用戶模式 下。
Native 應(yīng)用程序有哪些呢,當(dāng)然最出名的就是非法關(guān)機后用于磁盤檢查的AutoChk,當(dāng)Windows啟動起來后,你再想運行AutoChk.exe等 Native 應(yīng)用程序,你會得到一個
<應(yīng)用程序>無法在 Win32 模式下運行
的錯誤提示。
Native能干什么呢,想必你聽說過PQMagic,當(dāng)你掛起動態(tài)分區(qū),重新啟動電腦時,PQMagic就運行了一個Native應(yīng)用程序來執(zhí)行操作,這就是因為系統(tǒng)還沒有正常啟動起來,所以你可以做好多好多系統(tǒng)啟動后不能做的事情。ps: 瑞星殺毒的 BSMain 也是一個 Native 應(yīng)用程序。
編寫 Native應(yīng)用程序是不容易的,甚至你要調(diào)用的 API 微軟都不愿意公開,我們的入門資料是 Mark Russinovich 寫的《InsideNative Application》,網(wǎng)上有中文翻譯的文檔,可以參考,關(guān)于這篇文章,Mark 修改了多次,并且相差很多。關(guān)于其 API,參考資料是多年以前的一本電子書《Windows NT/2000 Native API Reference》。
一般來說,編寫 Native 應(yīng)用程序使用的是 DDK 或者 WDK 的 build,其實,VC 編譯器和鏈接器也知道如何生成此類程序,本文就介紹這種方法。
一般來說,你需要做如下配置:
***********************************************************************************************
General:
不使用MFC (Use Standard Windows Libraries)
使用Unicode字符集 (Use Unicode Character Set)
***********************************************************************************************
C/C++
-----------------------------------------------------------------------------------------------
General:
設(shè)置增加的 Include 文件目錄,當(dāng)然還應(yīng)當(dāng)包含其它的,用到時自己增加,
注意,此處已經(jīng)把 NDK 目錄拷貝到了 $(DDKROOT)\inc\ndk 下,不使用繼承目錄
Addtional Include Directories: "$(DDKROOT)\inc\ddk\wxp";"$(DDKROOT)\inc\ndk";$(NOINHERIT)
調(diào)試信息格式,如果不是調(diào)試版本,此處 Disable
Debug Information Format: Program Database (/Zi)
------------------------------------------------------------------------------------------------
Optimization:
禁止優(yōu)化,如果不是調(diào)試版本,此處 自己看著辦
Optimization: Disabled (/Od)
------------------------------------------------------------------------------------------------
Preprocessor:
預(yù)處理器定義,此處必須設(shè)置的是 _X86_ 其余的...
如果不是調(diào)試版本,DBG=0,以對應(yīng) DDK 中的 Free 版本
Preprocessor Definitions: _X86_;DBG=1;_WIN32_WINNT=0x0501
------------------------------------------------------------------------------------------------
Code Generation:
代碼生成,基本運行期檢查,關(guān)閉,不使用。
Basic Runtime Checks: Default
運行期庫,多線程調(diào)試
Runtime Library: Multi-threaded Debug DLL (/MDd)
------------------------------------------------------------------------------------------------
Precomplied Headers:
不使用預(yù)編譯頭(不好意思,習(xí)慣而已)
Create/Use Precomplied Header: Not Using Precompiled Headers
------------------------------------------------------------------------------------------------
***********************************************************************************************
Linker
------------------------------------------------------------------------------------------------
Gneral:
啟用增量鏈接,關(guān)閉,不使用
Enable Incremental Linking: No (/INCREMENTAL:NO)
增加的 lib 文件目錄
Additional Library Directories: "$(DDKROOT)\lib\wxp\i386"
------------------------------------------------------------------------------------------------
Input:
增加的 lib 文件,或者可以使用 #pragma comment(lib, "ntdll.lib)... 代替之
Additional Dependencies: ntdll.lib nt.lib $(NOINHERIT)
忽略所有默認庫文件
Ignore All Default Libraries: Yes (/NODEFAULTLIB)
------------------------------------------------------------------------------------------------
Debugging
生成調(diào)試信息,即使不是調(diào)試版本,此處 也可以生成
Generate Debug Information: Yes (/DEBUG)
------------------------------------------------------------------------------------------------
System:
子系統(tǒng)為 Native
Subsystem: Native (/SUBSYSTEM:NATIVE)
------------------------------------------------------------------------------------------------
Advanced:
入口函數(shù),其實 Native 默認的就是這個,可以不設(shè)置
Entry Point: NtProcessStartup
加載基地址,內(nèi)核部署,默認也是這個,可以不設(shè)置
Base Address: 0x10000
------------------------------------------------------------------------------------------------
***********************************************************************************************
配置確實挺多的,為此,我用 VS 2008 寫了一個 Wizard ,因為本文為了調(diào)試,所以沒有修改 Release 配置,
http://files.cnblogs.com/ChongyangLee/MyWizard.rar
這個壓縮文件中包含工程源代碼文件,
http://files.cnblogs.com/ChongyangLee/MyWizard_.rar
這個壓縮文件 不 包含工程源代碼文件,正常使用的話可以使用這個方法如下
其實,如果你使用我上面提供的向?qū)?,一個例子程序已經(jīng)寫好了,正如上面所提到的,用 VC 創(chuàng)建 Native 應(yīng)用程序時,默認的入口函數(shù)為NtProcessStartup,其參數(shù)為 PPEB,其實,使用 DDK 創(chuàng)建 Native 應(yīng)用程序時,可以創(chuàng)建 main函數(shù)就行了,NtProcessStartup 自動創(chuàng)建好了, 下面是我在向?qū)е刑峁┑睦哟a
1 #ifdef __cplusplus
2 extern "C" {
3 #endif/*__cplusplus*/
4 #include <ntndk.h>
5 #ifdef __cplusplus
6 }/* extern "C" */
7 #endif/*__cplusplus*/
8
9
10 #include <stdio.h>
11
12 //Handle of Heap
13 HANDLE g_hHeap;
14
15
16 void NtProcessStartup(PPEB ppeb)
17 {
18 //for Debug
19 __asm
20 {
21 int 3;//DbgBreakpoint()
22 }
23 DbgPrint("************START************");
24
25
26 RTL_HEAP_PARAMETERS parameter;
27 memset(¶meter, 0, sizeof(RTL_HEAP_PARAMETERS));
28 parameter.Length = sizeof(RTL_HEAP_PARAMETERS);
29
30 //Create Heap
31 g_hHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, 0x100000, 0x1000, NULL, ¶meter);
32
33 //todo:
34
35 UNICODE_STRING wBuf;
36 wBuf.Buffer = static_cast<wchar_t*>(RtlAllocateHeap(g_hHeap, 0, 255));
37
38 RtlInitUnicodeString(&wBuf, ppeb->ProcessParameters->CommandLine.Buffer);
39
40 NtDisplayString(&wBuf);
41 RtlFreeHeap(g_hHeap, 0, wBuf.Buffer);
42
43
44 UNICODE_STRING HelloMsg = RTL_CONSTANT_STRING(L"\nOne World, One Dream!\nBeiJing China");
45 NtDisplayString(&HelloMsg);
46
47
48 HANDLE hFile = NULL;
49 OBJECT_ATTRIBUTES objAttr = {0};
50 IO_STATUS_BLOCK IoStatusBlock = {0};
51 UNICODE_STRING wszPath = {0};
52
53 RtlInitUnicodeString(&wszPath, L"\\??\\c:\\abcd.txt");
54 InitializeObjectAttributes(&objAttr, &wszPath, 0, NULL, NULL);
55 NTSTATUS statusFile = NtCreateFile(&hFile, GENERIC_READ, &objAttr, &IoStatusBlock,
56 NULL, 0, FILE_SHARE_READ, FILE_OPEN_IF, 0, NULL, 0);
57
58
59
60 if(hFile != NULL)
61 {
62 NtClose(hFile);
63 }
64
65 //Terminate Manual
66 NtTerminateProcess(NtCurrentProcess(), 0);
67 }
68
69
上面的代碼完成了什么功能,
首先,在 Native 應(yīng)用程序中,堆是自己來創(chuàng)建并維護的;
第二,顯示了兩串字符,其一是從 PPEB 中取得的命令行信息,其二是一串固定的字符串;
第三,在 C 盤的根目錄下打開或者創(chuàng)建了一個文本文件,沒有操作,直接關(guān)閉了;
第四,終止該程序(return 是終止不了的)。
演示一下效果吧,
如果你去掉為了調(diào)試加的代碼(__asm{int 3;} DbgPrint("************START************");)編譯生成的程序,拷貝到你的System32目錄下,修改注冊表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
鍵:BootExecute
值:autocheck autochk *
<你的應(yīng)用程序名稱,此處假定為try3> xixihaha
重新啟動 Windows (不帶 /NOGUIBOOT 參數(shù)),你會在登錄前看到如下畫面
此處使用的是Session Manager 啟動的 Native Application,當(dāng)然還有其他的方法,自己google吧。
編寫程序不可能離開調(diào)試,但 Native應(yīng)用程序調(diào)試是困難的,需要進行內(nèi)核調(diào)試,因此你需要一個可以進行內(nèi)核調(diào)試的工具,SoftIce 或者WinDBG,本文中使用了后者。為了調(diào)試,你需要將前面加入的調(diào)試代碼打開,讓W(xué)indows運行到你的程序開頭時可以中斷。下面是不太詳細(需要你對WinDBG 有一定的了解)的詳細的調(diào)試過程:
待續(xù)