Windows Embedded CE 6.0 Internals (4) The Mechanism of API

来源:互联网 发布:python sleep 编辑:程序博客网 时间:2024/05/23 00:10


作者: 王克伟
出处: http://wangkewei.cnblogs.com/

引言

在调用系统提供的(System call)或者自己实现的DLL文件(有导出函数)中的API时,我很好奇其中的机制,也就是:我们为什么能调用这些API? 另外,安全和效率总是矛盾的,那么CE如何保证这两者? 现在的CE是不是不堪一击,用户态进程无意的操作是否就能让系统Crash,或者几行Shellcode就能瓦解它的安全体系?

这个问题让我想起来前几天看到的新闻,关于Windows桌面操作系统和Mac系统安全性的比较,就像查理·米勒所说的:

“Mac OS X就像是你生活在一所乡村里的,没有锁的房子,而Windows则是一间只有门闩的城市公寓。”

笔者尝试搞清楚其中的一些问题,欢迎交流,如发现文章错误或者欠妥的地方,请不吝赐教。

 

1.什么是系统调用?

“In computing, a system call is the mechanism by which a program requests a service from an operating system'skernel.”

简单的说就是系统内核提供给程序各种服务的一种方法。与系统调用类似的还有异常、中断(参加WindowsCE异常和中断服务程序初探或者《Windows Internals》)。

“On Unix, Unix-like and otherPOSIX-compatible Operating Systems, popular system calls areopen,read,write,close,wait,exec,fork,exit, andkill. Many of today's operating systems have hundreds of system calls. For example,Linux has 319 different system calls. Similarly,FreeBSD has almost 330.”

系统调用机制可增加安全性,操作系统能更容易的控制应用程序的权限。但是为了提高效率,CE系统会根据调用者是内核态的还是用户态的来做不同的处理,这也是内核态驱动比用户态驱动快的一个原因。

另一方面除了这些直接的系统API可用外,我们还经常看到一些库,这些库处于程序和操作系统之间,比如C library,这些库实现更好的跨平台性(portability)。更高层的,比如.Net Framework,能够提供更方便、更快捷的开发环境。

 

2.系统调用的基本实现原理

我们一般使用 software interrupt 或者 trap 的方式实现CPU控制权的转移。那么当触发一个系统调用时,CPU的执行特权等级会改变(比如ring 3->0),如何实现?

在较早的X86系统中,我们使用call gate机制,而现代系统的使用SYSENTER/SYSEXIT(Intel)和SYSCALL/SYSRET(AMD):
SYSENTER——快速系统调用
sysenter/sysexit 指令
Implement system call withsysenter/sysexit

不知道Android系统调用机制如何(Linux的系统调用机制),期待看到这样的文章,这里有份简单的文档:
http://ubuntubd.files.wordpress.com/2009/12/linux-system-call-quick-reference.pdf

系统调用大致可以分为以下5个种类:

  1. Process Control.
    • end, abort
    • load, execute
    • create process, terminate process
    • get process attributes, set process attributes
    • wait for time
    • wait event, signal event
    • allocate and free memory
  2. File management.
    • create file, delete file
    • open, close
    • read, write, reposition
    • get file attributes, set file attributes
  3. Device Management.
    • request device, release device
    • read, write, reposition
    • get device attributes, set device attributes
    • logically attach or detach devices
  4. Information Maintenance.
    • get time or date, set time or date
    • get system data, set system data
    • get process, file, or device attributes
    • set process, file, or device attributes
  5. Communication.
    • create, delete communication connection
    • send, receive messages
    • transfer status information
    • attach or detach remote devices

 

3.CE中的具体实现

在CE中coredll.dll文件的作用比较类似于桌面操作系统kernel32.dll的作用。我们看看维基百科中的关于kernel32.dll的介绍:

Base Services[3]
Provide access to the fundamental resources available to a Windows system. Included are things likefile systems,devices,processes andthreads, and error handling. These functions reside in kernel.exe, krnl286.exe orkrnl386.exe files on 16-bit Windows, and kernel32.dll on 32-bit Windows.

 更多请看这里:Windows API -Wikipedia, the free encyclopedia

另外我们注意到 k.coredll.dll 是内核版本的coredll.dll,更多请参考:Windows Embedded CE 6.0 Internals (1) Kernel Overview

“The kernel-mode servers are supported by a kernel-only version of COREDLL, named K.COREDLL.DLL. Any code that loads into the kernel but was linked against COREDLL.DLL, is automatically redirected to use K.COREDLL.DLL instead. ”

下文我们一直围绕着一个问题开展:从应用层发起的API调用首先会定位到coredll.dll中的位置,如何定位?

打开\PRIVATE\WINCEOS\COREOS\NK\INC\nkarm.h,我们看到一些结构:

我们看到KDataStruct这个结构(这个结构在CE 4.0和6.0上有所不同),其开始地址是固定的PUserKData(参考\PUBLIC\COMMON\SDK\INC\ kfuncs.h),对于ARM处理器是0xFFFFC800,而其它处理器是0x00005800。

aInfo[32]中详细布局如下(参考\PUBLIC\COMMON\OAK\INC\pkfuncs.h):

偏移KINFO_OFFSET(即0x300)的是UserKInfo数组,里面保存了重要的系统数据,比如模块链表、内核堆、APIset pointers表(SystemAPISets)。

偏移0x324的aInfo[KINX_MODULES]是一个指向模块链表的指针,通过这个链表可以找到coredll.dll模块。(更详细的资料请参考:Windows CE初探,但是该文章介绍的是较早的CE 4.2,CE 6.0可能有所区别。)

APIset pointers表存放在UserKInfo[KINX_APISETS]处。从下图我们能更直观的看到内存映射,但是该图是CE 4.2的,CE 6.0在KINFO_OFFSET以上部分有所不同。

clip_image001


打开\PUBLIC\COMMON\SDK\INC\kfuncs.h我们发现:

CE目前支持128个API集。

“API机制使用了PSLs(protected server libraries),是一种客户端/服务端模式。PSLs象DLL一样处理导出服务,服务的导出通过注册APIset。

有两种类型的APIset,分别是固有的和基于句柄的。固有的API sets注册在全局表SystemAPISets中,可以以API句柄索引和方法索引的组合来调用他们的方法。基于句柄的API和内核对象相关,如文件、互斥体、事件等。这些API的方法可以用一个对象的句柄和方法索引来调用。

kfuncs.h中定义了固有APIset的句柄索引(上面的代码可见),如:SH_WIN32、SH_GDI、SH_WMGR等。基于句柄的API索引定义在\PUBLIC\COMMON\OAK\INC\psyscall.h中,如:HT_EVENT、HT_APISET、HT_SOCKET等。

SystemAPISets共有32个CINFO结构的APIset,通过遍历SystemAPISets成员,可以列出系统所有API。”(引用自Windows CE API机制初探)


其中CINFO的结构在\PRIVATE\WINCEOS\COREOS\NK\INC\apicall.h和\PRIVATE\WINCEOS\COREOS\NK\INC\kerncmn.h中定义:

“Windows CE没有使用ARM处理器的SWI指令来实现系统调用,SWI指令在Windows CE里是空的,就简单的执行了"movs pc,lr"(详见armtrap.s关于SWIHandler的实现)。Windows CE的系统调用使用了0xf0000000 - 0xf0010000的地址,当系统执行这些地址的时候将会触发异常,产生一个PrefetchAbort的trap。在PrefetchAbort的实现里(详见armtrap.s)首先会检查异常地址是否在系统调用trap区,如果不是,那么执行ProcessPrefAbort,否则执行ObjectCall查找API地址来分派。

通过APIset和其API的索引可以算出系统调用地址,其公式是:0xf0010000-(256*apiset+apinr)*4。比如对于SC_CreateAPISet的系统调用可以这样算出来:0xf0010000-(256*0+2)*4=0xF000FFF8。”(引用自Windows CE API机制初探,在CE 6.0上这个还有待验证。)

了解了其中的原理之后,我们可以实现API的劫持,以便满足一些需求,比如文件监控,当然也能干些见不得人的事。我还存在的疑问是:

UserKInfo[KINX_APISETS]在什么时候初始化?怎么初始化?

coredll.dll如何对API进行包裹的?

疑问还非常多,这些问题以后慢慢挖掘吧,今天头已经大了。

0 0
原创粉丝点击