关于本机API的讨论网上已经比较多了。本机API是除了Win32 API,NT平台开放了另一个基本接口。本机API由于它本身运行在Ring0层,接近系统内核,拥有没有限制操作权限,因此微软没有发布支持这种应用的开发方法。尽管如此,并不一定需要驱动级别去访问这个接口,普通的Win32程序可以在任何时候向下调用本机API。
Win32 API中的所有调用最终都转向了ntdll.dll,再由它转发至ntoskrnl.exe。ntdll.dll是本机 API用户模式的终端。真正的接口在ntoskrnl.exe里完成。事实上,内核模式的驱动大部分时间调用这个模块,如果它们请求系统服务。Ntdll.dll的主要作用就是让内核函数的特定子集可以被用户模式下运行的程序调用。Ntdll.dll通过软件中断int 2Eh进入ntoskrnl.exe,也就是通过中断门切换CPU特权级。 关于这方面的讨论网上已有不少了,这里就不多说了。言归正传,如何在用户模式下调用本机API呢?
想要从用户模式下调用本机API函数,必须考虑到以下四点:
1 SDK头文件没有包括这些函数的原型
2 这些函数使用的若干基本数据类型没有包括在SDK文件中
3 SDK和DDK头文件不兼容,不能在win32的c源文件包含ntddk.h中
4 ntdll.lib没有包括在VC的默认导入库列表中。
第4个很容易解决:#progma comment(linker,“/defaultlib:ntdll.lib”)
缺失的定义比较难解决,最简单的方法是写一个自定义的头文件,刚刚包含需要调用ntdll.dll中函数的定义。幸运的是,已经有人做了这个工作。Sven B. Schreiber编写了一个叫“w2k_def.h”的头文件,这个头文件包含需要调用ntdll.dll中函数的定义并可用于用户模式和内核模式程序,所以只需在用户模式代码中#include<w2k_def.h>之前#define _USER_MODE_,使得DDK中出现而SDK中没有的定义可用即可。
下面有个例子供大家参考:
#include <stdio.h>
#include "windows.h"
#define _USER_MODE_
#include <w2k_def.h>
#pragma comment(linker,"/defaultlib:ntdll.lib")
typedef ULONG (CALLBACK* DBGPRINT)(PCHAR,...);
typedef int (CALLBACK* NtGETTICKCOUNT)();
DBGPRINT DbgPrint;
NtGETTICKCOUNT NtGetTickCount;
int main()
{
HMODULE hNtDll;
hNtDll = LoadLibrary( "ntdll.dll" );
if(!hNtDll)
{
printf( "LoadLibrary( NTDLL.DLL ) Error:%d\n", GetLastError() );
return false;
}
DbgPrint = (DBGPRINT)GetProcAddress(hNtDll, "DbgPrint");
NtGetTickCount = (NtGETTICKCOUNT)GetProcAddress(hNtDll, "NtGetTickCount");
int iTime = NtGetTickCount();
DbgPrint("The TickCount is: %d\n",iTime);
DbgPrint("hello\n");
return 0;
}
DbgPrint输出可用用DS的DriverMonitor看到。