浅析本机API
<P><FONT color=#ff3300>作者:sunwear </FONT><a href="mailtshellcoder@163.com" target="_blank" ><FONT color=#ff3300>shellcoder@163.com</FONT></A><FONT color=#ff3300>来源:邪恶八进制 中国</FONT></P>
<P>此文只能说是一篇笔记,是关于本机API的.本机API是除了Win32 API,NT平台开放了另一个基本接口。本</P>
<P>机API也被很多人所熟悉,因为内核模式模块位于更低的系统级别,在那个级别上环境子系统是不可见的</P>
<P>。尽管如此,并不需要驱动级别去访问这个接口,普通的Win32程序可以在任何时候向下调用本机API。并</P>
<P>没有任何<a href="http://hackbase.com/network" target="_blank" >技术</A>上的限制,只不过微软不支持这种应用开发方法。
</P>
<P>User32.dll,kernel32.dll,shell32.dll,gdi32.dll,rpcrt4.dll,comctl32.dll,advapi32.dll,version.d</P>
<P>ll等dll代表了Win32 API的基本提供者。Win32 API中的所有调用最终都转向了ntdll.dll,再由它转发至</P>
<P>ntoskrnl.exe。ntdll.dll是本机 API用户模式的终端。真正的接口在ntoskrnl.exe里完成。事实上,内</P>
<P>核模式的驱动大部分时间调用这个模块,如果它们请求系统<a href="http://vip.hackbase.com/" target="_blank" >服务</A>。Ntdll.dll的主要作用就是让内核函数</P>
<P>的特定子集可以被用户模式下运行的程序调用。Ntdll.dll通过<a href="http://down.hackbase.com/" target="_blank" >软件</A>中断int 2Eh进入ntoskrnl.exe,就是</P>
<P>通过中断门切换CPU特权级。比如kernel32.dll导出的函数DeviceIoControl()实际上调用ntdll.dll中导</P>
<P>出的NtDeviceIoControlFile(),反汇编一下这个函数可以看到,EAX载入magic数0x38,实际上是系统调</P>
<P>用号,然后EDX指向堆栈。目标地址是当前堆栈指针ESP+4,所以EDX指向返回地址后面一个,也就是指向</P>
<P>在进入NtDeviceIoControlFile()之前存入堆栈的东西。事实上就是函数的参数。下一个指令是int 2Eh,</P>
<P>转到中断描述符表IDT位置0x2E处的中断处理程序。</P>
<P>反编汇这个函数得到:</P>
<P>mov eax, 38h</P>
<P>lea edx, </P>
<P>int 2Eh</P>
<P>ret 28h</P>
<P>当然int 2E接口不仅仅是简单的API调用调度员,他是从用户模式进入内核模式的main gate。</P>
<P>W2k Native API由248个这么处理的函数组成,比NT 4.0多了37个。可以从ntdll.dll的导出列表中很容易</P>
<P>认出来:前缀Nt。Ntdll.dll中导出了249个,原因在于NtCurrentTeb()为一个纯用户模式函数,所以不需</P>
<P>要传给内核。令人惊奇的是,仅仅Native API的一个子集能够从内核模式调用。而另一方面,</P>
<P>ntoskrnl.exe导出了两个Nt*符号,它们不存在于ntdll.dll中: NtBuildNumber, NtGlobalFlag。它们不</P>
<P>指向函数,事实上,是指向ntoskrnl.exe的变量,可以被使用C编译器extern关键字的驱动模块导入。</P>
<P>Ntdll.dll和ntoskrnl.exe中都有两种前缀Nt*,Zw*。事实上ntdll.dll中反汇编结果两者是一样的。而在</P>
<P>ntoskrnl.exe中,nt前缀指向真正的<a href="http://hackbase.com/hacker" target="_blank" >代码</A>,而zw还是一个int 2Eh的stub。也就是说zw*函数集通过用户模</P>
<P>式到内核模式门传递的,而Nt*符号直接指向模式切换以后的<a href="http://hackbase.com/hacker" target="_blank" >代码</A>。Ntdll.dll中的NtCurrentTeb()没有相</P>
<P>对应的zw函数。Ntoskrnl并不导出配对的Nt/zw函数。有些函数只以一种方式出现。</P>
<P>2Eh中断处理程序把EAX里的值作为查找表中的索引,去找到最终的目标函数。这个表就是系统<a href="http://vip.hackbase.com/" target="_blank" >服务</A>表SST</P>
<P>,C的结构SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE的定义如下:清单也包含了结构SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE中的定义,为</P>
<P>SST数组第四个成员,前两个有着特别的用途。</P>
<P>typedef NTSTATUS (NTAPI *NTPROC) ( ) ;</P>
<P>typedef NTPROC *PNTPROC;</P>
<P>#define NTPROC<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> sizeof (NTPROC)</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE</P>
<P>{ PNTPROC ServiceTable; // 这里是入口指针数组</P>
<P>PDWORD CounterTable; // 此处是调用次数计数数组</P>
<P>DWORD ServiceLimit ; // <a href="http://vip.hackbase.com/" target="_blank" >服务</A>入口的个数</P>
<P>PBYTE ArgumentTable; // <a href="http://vip.hackbase.com/" target="_blank" >服务</A>参数字节数的数组</P>
<P>) SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE ,</P>
<P>* PSYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE ,</P>
<P>* * PPSYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE ;</P>
<P>/ / <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A></P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE</P>
<P>{ SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE ntoskrnl ; // ntoskrnl所实现的系统<a href="http://vip.hackbase.com/" target="_blank" >服务</A>,本机的API}</P>
<P>SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE win32k; // win32k所实现的系统<a href="http://vip.hackbase.com/" target="_blank" >服务</A></P>
<P>SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE Table3; // 未使用</P>
<P>SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE Table4; // 未使用</P>
<P>} SERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE ,</P>
<P>* PSERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE,</P>
<P>* PPSERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE ;</P>
<P>ntoskrnl通过KeServiceDescriptorTable符号,导出了主要SDT的一个指针。内核维护另外的一个SDT,就</P>
<P>是KeServiceDescriptorTableShadow。但这个符号没有导出。要想在内核模式组件中存取主要SDT很简单</P>
<P>,只需两行C语言的<a href="http://hackbase.com/hacker" target="_blank" >代码</A>:</P>
<P>extern PSERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE KeServiceDescriptorTable;</P>
<P>PSERVICE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>DESCRIPTOR<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>TABLE psdt= KeServiceDescriptorTable;</P>
<P>NTPROC为本机 API的方便的占位符,他类似于Win32<a href="http://hackbase.com/hacker/program" target="_blank" >编程</A>中的PROC。Native API正常的返回应该是一个</P>
<P>NTSTATUS<a href="http://hackbase.com/hacker" target="_blank" >代码</A>,他使用NTAPI调用约定,它和<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>stdcall一样。ServiceLimit成员有在ServiceTable数组里</P>
<P>找到的入口数目。在2000下,默认值是248。ArgumentTable为BYTEs的数组,每一个对应于ServiceTable</P>
<P>的位置并显示了在调用者堆栈里的参数比特数。这个信息与EDX结合,这是内核从调用者堆栈copy参数到</P>
<P>自己的堆栈所需的。CounterTable成员在free buid的2000中并没有使用到,在debug build中,这个成员</P>
<P>指向代表所有函数使用计数的DWORDS数组,这个信息能用于性能分析。
可以使用这个命令来显示:dd KeServiceDescriptorTable,调试器把此符号解析为0x8046e0c0。只有</P>
<P>前四行是最重要的,对应那四个SDT成员。
运行这个命令:ln 8046e100,显示符号是KeServiceDescriptorTableShadow,说明第五个开始确实为</P>
<P>内核维护的第二个SDT。主要的区别在于后一个包含了win32k.sys的入口,前一个却没有。在这两个表中</P>
<P>,Table3与Table4都是空的。Ntoskrnl.exe提供了一个方便的API函数。这个函数的名字为:</P>
<P> KeAddSystemServiceTable
此函数去填充这些位置。</P>
<P>2Eh的中断处理标记是KisystemService()。这也是ntoskrnl.exe没有导出的内部的符号,但包含在2k符号</P>
<P>文件中。关于KisystemService的操作如下:</P>
<P>1 从当前的线程控制块检索SDT指针</P>
<P>2 决定使用SDT中4个SST的其中一个。通过测试EAX中递送ID的第12和13位来决定。ID在0x0000-0x0fff的</P>
<P>映射至ntoskrnl表格,ID在</P>
<P>0x1000与0x1ffff的分配给win32k表格。剩下的0x2000-0x2ffff与</P>
<P>0x3000-0x3ffff则是Table3和Table4保留。</P>
<P>3 通过选定SST中的ServiceLimit成员检查EAX的0-11位。如果ID超过了范围,返回错误<a href="http://hackbase.com/hacker" target="_blank" >代码</A>为</P>
<P>STATUS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INVALID<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SYSTEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>SERVICE。</P>
<P>4 检查EAX中的参数堆栈指针与MmUserProbeAddress。这是一个ntoskrnl导出的全局变量。通常等于</P>
<P>0x7FFF0000,如果参数指针不在这个地址之下,返回STATUS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ACCESS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>VIOLATION。</P>
<P>5 查找ArgumentTable中的参数堆栈的字节数,从调用者的堆栈copy所有的参数至当前内核模式堆栈。</P>
<P>6 搜索serviceTable中的<a href="http://vip.hackbase.com/" target="_blank" >服务</A>函数指针,并调用这个函数。</P>
<P>7 控制转到内部的函数KiserviceExit,在此次<a href="http://vip.hackbase.com/" target="_blank" >服务</A>调用返回之后。</P>
<P>从对SDT的讨论可以看到与本机API一起还有第二个内核模式接口。这个接口把Win32子系统的图形设备接</P>
<P>口和窗口管理器和内核模式组件Win32k连接起来。Win32k接口一样是基于int 2eh。本机API的<a href="http://vip.hackbase.com/" target="_blank" >服务</A>号是从</P>
<P>0x0000到0x0fff,win32k的<a href="http://vip.hackbase.com/" target="_blank" >服务</A>号是从0x1000到0x1fff。(ddW32pServiceTable认定win32k.sys的符号可</P>
<P>用。)win32k总共包含639个系统<a href="http://vip.hackbase.com/" target="_blank" >服务</A>。</P>
<P>
2Eh的处理过程没有使用全局SDT KeServiceDescriptorTable。</P>
<P>而是一个与线程相关的指针。显然,线程可以有不同得SDT相关到自身。线程初试化的时</P>
<P>候,KeInitializeThread()把KeServiceDescriptorTable写到线程的控制块。尽管这样,这个默认设置之</P>
<P>后可能被改变为其它值,例如KeServiceDescriptorTableShadow。</P>
<P>
Windows 2000运行时库</P>
<P>Ntdll.dll至少导出了不少于1179个符号。其中的249/248是属于Nt*/zw*集合。所以还有682个函数不是通</P>
<P>过int 2eh门中转。很显然,这么多的函数不依靠2k的内核。</P>
<P>其中一些是和c运行时库几乎一样的函数。其实ntoskrnl也实现了一些类似C运行时库的一些函数。可以</P>
<P>通过ddk里的ntdll.lib来链接和使用这些函数。反汇编ntdll.dll与ntoskrnl.exe的C运行时函数能发现</P>
<P>,ntdll.dll并不是依赖ntoskrnl.exe。这两个模块各自实现了这些函数。</P>
<P>除了C运行时库外,2000还提供了一个扩展的运行时函数集合。再一次,ntdll.dll与ntoskrnl.exe各自</P>
<P>实现了它们。同样,实现集合有重复,但是并不完全匹配。这个集合的函数都是以Rtl开头的。2000运行</P>
<P>时库包括一些辅助函数用于C运行时候无法完成的任务。例如有些处理安全事务,另外的操纵2000专用的</P>
<P>数据结构,还有些支持内存管理。微软仅仅在DDK中记录了很有用的406个函数中的115个函数。</P>
<P>Ntdll.dll还提供了另外一个函数集合,以<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A><a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>e前缀开头。实际上它们用于浮点数模拟器。</P>
<P>还有很多的函数集合,所有这些函数的前缀如下:</P>
<P><a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A><a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>e(浮点模拟),Cc(Cache管理),Csr(c/s运行时库),Dbg(调试支持),Ex(执行支持),FsRtl(文件系统运行</P>
<P>时),Hal(硬件抽象层),Inbv(系统初试化/vga启动驱动程序bootvid.dll),Init(系统初试</P>
<P>化),Interlocked(线程安全变量操作),Io(IO管理器),Kd(内核调试器支持),Ke(内核例程),Ki(内核中断处</P>
<P>理),Ldr(映象装载器),Lpc(本地过程调用),Lsa(本地安全授权),Mm(内存管理),Nls(国际化语言支持),Nt</P>
<P>(NT本机API),Ob(对象管理器),Pfx(前缀处理),Po(电源管理),Ps(进程支持),READ<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>REGISTER<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>(从寄存器</P>
<P>地址读),Rtl(2k运行时库),Se(安全处理),WRITE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>REGISTER<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>(写寄存器地址),Zw(本机API的替换叫法)</P>
<P>,<其它>(辅助函数和C运行时库)。</P>
<P>当编写从用户模式通过ntdll.dll或内核模式通过ntoskrnl.exe和2000内核交互的<a href="http://down.hackbase.com/" target="_blank" >软件</A>的时候,需要处理</P>
<P>很多基本的数据结构,这些结构在Win32世界中很少见到。</P>
<P>常用数据结构</P>
<P>l 整数</P>
<P>ANSI字符是有符号的,而Unicode WCHAR是无符号的</P>
<P>MASM的TBYTE是80位的浮点数,用于高精度浮点运算单元操作,注意它与Win32的TBYTE(text byte)完全</P>
<P>不同。</P>
<P>TABLE 2-3. Equivalent Integral Data Types</P>
<P>BITS MASM FUNDAMENTAL ALIAS #1 ALIAS #2 SIGNED</P>
<P>8 BYTE unsigned char UCHAR CHAR
16 WORD unsigned short USHORT WCHAR SHORT</P>
<P>32 DWORD unsigned long ULONG LONG</P>
<P>32 DWORD unsigned int UINT INT</P>
<P>64 QWORD unsigned <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>int64 ULONGLONG DWORDLONG LONGLONG</P>
<P>80 TBYTE N/A</P>
<P>typedef union <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>LARGE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INTEGER</P>
<P>{ struct{</P>
<P>ULONG LowPart;</P>
<P>LONG HighPart;};</P>
<P>LONGLONG QuadPart;</P>
<P>}</P>
<P>LARGE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INTEGER , * PULARGE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INTEGER ;</P>
<P>typedef union <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ULARGE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INTEGER{</P>
<P>struct{</P>
<P>ULONG LowPart;</P>
<P>ULONG HighPart;}</P>
<P>ULONGLONG QuadPart;</P>
<P>}ULARGE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INTEGER, *PULARGE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>INTEGER;</P>
<P>l 字符</P>
<P> Win32<a href="http://hackbase.com/hacker/program" target="_blank" >编程</A>中PSTR用户CHAR*,PWSTR用于WCHAR*。取决于是否定义了UNICODE,PTSTR解释为PSTR或者</P>
<P>PWSTR。在2k内核模式下,常用的数据类型是UNICODE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING,而STRING用来表示ANSI字符串:</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>UNICODE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING{</P>
<P>USHORT Length; //当前字节长度,不是字符!!!</P>
<P>USHORT MaximumLength; //Buffer的最大字节长度</P>
<P>PWSTR Buffer;}UNICODE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING , * PUNICODE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING ;</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING{</P>
<P>USHORT Length;</P>
<P>USHORT MaximumLength;</P>
<P>PCHAR Buffer;}STRING, *PSTRING;</P>
<P>typedef STRING ANSI<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING, *PANSI<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING;</P>
<P>typedef STRING OEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING, *POEM<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING;</P>
<P>操纵函数:RtlCreatUnicodeString(),RtlInitUnicodeString(),</P>
<P>RtlCopyUnicodeString()等等</P>
<P>l 结构</P>
<P>许多内核API函数需要一个固定大小的OBJECT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ATTRIBUTES结构,比如NtOpenFile()。对象的属性是OBJ<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>*</P>
<P>值的组合,可以从ntdef.h中查到。</P>
<P>IO<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STATUS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>BLOCK结构提供了所请求操作结果的信息,很简单,status成员包含一个NTSTATUS<a href="http://hackbase.com/hacker" target="_blank" >代码</A>, 如果</P>
<P>操作成功 information成员提供特定请求的信息。</P>
<P>还有一个结构是LIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY,这是一个双向环链表。</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>OBJECT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ATTRIBUTES</P>
<P>{</P>
<P>ULONG Length;</P>
<P>HANDLE RootDirectory;</P>
<P>PUNICODE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STRING ObjectName;</P>
<P>ULONG Attributes;</P>
<P>PVOID SecurityDescriptor;</P>
<P>PVOID SecurityQualityOfService;</P>
<P>} OBJECT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ATTRIBDTES, *POBJECT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A> ATTRIBUTES;</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>IO<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STATUS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>BLOCK</P>
<P>{</P>
<P>NTSTATDS Status;</P>
<P>ULONG Information;</P>
<P>}IO<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STATUS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>BLOCK , * PIO<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>STATUS<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>BLOCK ;</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>LIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY</P>
<P>{</P>
<P>Struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>LIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY *Flink;</P>
<P>Struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>LIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY *Blink;</P>
<P>}LIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY, *PLIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY;</P>
<P>双向链表的典型例子就是进程和线程链。内部变量PsActiveProcessHead是一个LIST<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ENTRY结构,在</P>
<P>ntoskrnl.exe的数据段中,指定了系统进程列表的第一个成员。</P>
<P>CLIENT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ID结构由进程和线程ID组成。</P>
<P>typedef struct <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>CLIENT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ID</P>
<P>{ HANDLE UniqueProcess;</P>
<P>HANDLE UniqueThread;</P>
<P>)CLIENT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ID, *PCLIENT<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>ID;</P>
<P>想要从用户模式调用ntdll.dll中的API函数,必须考虑到以下四点:</P>
<P>1 SDK头文件没有包括这些函数的原型</P>
<P>2 这些函数使用的若干基本数据类型没有包括在SDK文件中</P>
<P>3 SDK和DDK头文件不兼容,不能在win32的c源文件包含ntddk.h中</P>
<P>4 ntdll.lib没有包括在VC的默认导入库列表中。</P>
<P>第4个很容易解决:#progma comment(linker,“/defaultlib:ntdll.lib”)</P>
<P>缺失的定义比较难解决,最简单的方法是写一个自定义的头文件,刚刚包含需要调用ntdll.dll中函数的</P>
<P>定义。幸运的是,已经在光盘的w2k<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>def.h文件中做了这个工作。因为这个头文件将用于用户模式和内核</P>
<P>模式程序,所以必须在用户模式<a href="http://hackbase.com/hacker" target="_blank" >代码</A>中,#include<w2k<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>def.h>之前#define <a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>USER<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>MODE<a href="http://www3.hackbase.com/hacker/tutorial/200501239682.htm#" target="_blank" >_</A>,使得DDK中出</P>
<P>现而SDK中没有的定义可用。</P>
<P>
本文部分翻译于一篇电子书<win api about>.也感谢朋友GameHunter这位英语极好的朋友帮忙.与Free的</P>
<P>指导
</P>
<P>
<CENTER></CENTER>
页:
[1]