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个种类:
- 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
- File management.
- create file, delete file
- open, close
- read, write, reposition
- get file attributes, set file attributes
- Device Management.
- request device, release device
- read, write, reposition
- get device attributes, set device attributes
- logically attach or detach devices
- 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
- 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的介绍:
更多请看这里: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,我们看到一些结构:
/* High memory layout
*
* This structure is mapped in at the end of the 4GB virtual
* address space.
*
* 0xFFFD0000 - first level page table (uncached) (2nd half is r/o)
* 0xFFFD4000 - disabled for protection
* 0xFFFE0000 - second level page tables (uncached)
* 0xFFFE4000 - disabled for protection
* 0xFFFF0000 - exception vectors
* 0xFFFF0400 - not used (r/o)
* 0xFFFF1000 - disabled for protection
* 0xFFFF2000 - r/o (physical overlaps with vectors)
* 0xFFFF2400 - Interrupt stack (1k)
* 0xFFFF2800 - r/o (physical overlaps with Abort stack & FIQ stack)
* 0xFFFF3000 - disabled for protection
* 0xFFFF4000 - r/o (physical memory overlaps with vectors & intr. stack & FIQ stack)
* 0xFFFF4900 - Abort stack (2k - 256 bytes)
* 0xFFFF5000 - disabled for protection
* 0xFFFF6000 - r/o (physical memory overlaps with vectors & intr. stack)
* 0xFFFF6800 - FIQ stack (256 bytes)
* 0xFFFF6900 - r/o (physical memory overlaps with Abort stack)
* 0xFFFF7000 - disabled
* 0xFFFFC000 - kernel stack
* 0xFFFFC800 - KDataStruct
* 0xFFFFCC00 - disabled for protection (2nd level page table for 0xFFF00000)
*/
typedef
struct
ARM_HIGH {
ulong firstPT[4096];
// 0xFFFD0000: 1st level page table
char
reserved2[0x20000-0x4000];
char
exVectors[0x400];
// 0xFFFF0000: exception vectors
char
reserved3[0x2400-0x400];
char
intrStack[0x400];
// 0xFFFF2400: interrupt stack
char
reserved4[0x4900-0x2800];
char
abortStack[0x700];
// 0xFFFF4900: abort stack
char
reserved5[0x6800-0x5000];
char
fiqStack[0x100];
// 0xFFFF6800: FIQ stack
char
reserved6[0xC000-0x6900];
char
kStack[0x800];
// 0xFFFFC000: kernel stack
struct
KDataStruct kdata;
// 0xFFFFC800: kernel data page
} ARM_HIGH;
我们看到KDataStruct这个结构(这个结构在CE 4.0和6.0上有所不同),其开始地址是固定的PUserKData(参考\PUBLIC\COMMON\SDK\INC\ kfuncs.h),对于ARM处理器是0xFFFFC800,而其它处理器是0x00005800。
// NOTE: only kernel and coredll should access PUserKData directly
// or potentially BC Break once we move on to the next OS.
#if defined(_ARM_)
#define PUserKData ((LPBYTE)0xFFFFC800)
#else
#define PUserKData ((LPBYTE)0x00005800)
#endif
struct
KDataStruct {
#include "kdata_common.h"
// CPU Dependent part uses offset 0x2a0 - 0x300, and after aInfo
ulong dwArchitectureId;
// 0x2a0 architecture id
LPVOID
pAddrMap;
// 0x2a4 ptr to OEMAddressTable array
DWORD
dwRead;
// 0x2a8 - R/O, both kernel and user
DWORD
dwWrite;
// 0x2ac - R/W, both kernel and user
DWORD
dwKrwUno;
// 0x2b0 - Kernel R/W, user no access
DWORD
dwKrwUro;
// 0x2b4 - Kernel R/W, user no access
DWORD
dwProtMask;
// 0x2b8 - mask for all the permission bits
DWORD
dwOEMInitGlobalsAddr;
// 0x2bc ptr to OAL entry point
DWORD
dwTTBRCtrlBits;
// 0x2c0 - control bits for TTBR (see above TTBR Bit formats)
DWORD
dwPTExtraBits;
// 0x2c4 - extra bits for PT entry
long
alPad[14];
// 0x2c8 - padding
// aInfo MUST BE AT OFFSET 0x300
DWORD
aInfo[32];
/* 0x300 - misc. kernel info */
/* 0x380 - interlocked api code */
/* 0x400 - end */
};
/* KDataStruct */
aInfo[32]中详细布局如下(参考\PUBLIC\COMMON\OAK\INC\pkfuncs.h):
#define KINX_PROCARRAY 0 /* 0x300 address of process array */
#define KINX_PAGESIZE 1 /* 0x304 system page size */
#define KINX_PFN_SHIFT 2 /* 0x308 shift for page # in PTE */
#define KINX_PFN_MASK 3 /* 0x30c mask for page # in PTE */
#define KINX_PAGEFREE 4 /* 0x310 # of free physical pages */
#define KINX_SYSPAGES 5 /* 0x314 # of pages used by kernel */
#define KINX_KHEAP 6 /* 0x318 ptr to kernel heap array */
#define KINX_SECTIONS 7 /* 0x31c ptr to SectionTable array */
#define KINX_MEMINFO 8 /* 0x320 ptr to system MemoryInfo struct */
#define KINX_MODULES 9 /* 0x324 ptr to module list */
#define KINX_DLL_LOW 10 /* 0x328 lower bound of DLL shared space */
#define KINX_NUMPAGES 11 /* 0x32c total # of RAM pages */
#define KINX_PTOC 12 /* 0x330 ptr to ROM table of contents */
#define KINX_KDATA_ADDR 13 /* 0x334 kernel mode version of KData */
#define KINX_GWESHEAPINFO 14 /* 0x338 Current amount of gwes heap in use */
#define KINX_TIMEZONEBIAS 15 /* 0x33c Fast timezone bias info */
#define KINX_PENDEVENTS 16 /* 0x340 bit mask for pending interrupt events */
#define KINX_KERNRESERVE 17 /* 0x344 number of kernel reserved pages */
#define KINX_API_MASK 18 /* 0x348 bit mask for registered api sets */
#define KINX_NLS_CP 19 /* 0x34c hiword OEM code page, loword ANSI code page */
#define KINX_NLS_SYSLOC 20 /* 0x350 Default System locale */
#define KINX_NLS_USERLOC 21 /* 0x354 Default User locale */
#define KINX_HEAP_WASTE 22 /* 0x358 Kernel heap wasted space */
#define KINX_DEBUGGER 23 /* 0x35c For use by debugger for protocol communication */
#define KINX_APISETS 24 /* 0x360 APIset pointers */
#define KINX_MINPAGEFREE 25 /* 0x364 water mark of the minimum number of free pages */
#define KINX_CELOGSTATUS 26 /* 0x368 CeLog status flags */
#define KINX_NKSECTION 27 /* 0x36c Address of NKSection */
#define KINX_PWR_EVTS 28 /* 0x370 Events to be set after power on */
#define KINX_NKSIG 31 /* 0x37c last entry of KINFO -- signature when NK is ready */
/* 0x380 - interlocked api code */
/* 0x400 - end */
偏移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以上部分有所不同。
打开\PUBLIC\COMMON\SDK\INC\kfuncs.h我们发现:
//
// We now support 128 API sets. Where the API numbers are defined as follows
//
// 0: kernel WIN32 API set
// 1-63: OS reserved Handle based API sets
// 64-79: partner defined Handle based API sets
// 80-111: OS reserved non-handle based API sets
// 112-127:partner defined non-hnadle based API sets
//
// non-handle-based APIs (API set 80-127) will receive PSL notifications.
//
//
#define SH_FIRST_OS_HAPI_SET 1 // 1st OS, handle based API set
#define SH_FIRST_EXT_HAPI_SET 64 // 1st partner defined handle based API set
#define SH_FIRST_OS_API_SET 80 // 1st OS non-handle based API set
#define SH_FIRST_EXT_API_SET 112 // 1st partner defined non-handle based API set
#define SH_WIN32 0
#define SH_CURTHREAD 1
#define SH_CURPROC 2
#define SH_CURTOKEN 3
// Special handle indicies used for "typed" handle calls
#define HT_EVENT 4 // Event handle type
#define HT_MUTEX 5 // Mutex handle type
#define HT_APISET 6 // kernel API set handle type
#define HT_FILE 7 // open file handle type
#define HT_FIND 8 // FindFirst handle type
#define HT_DBFILE 9 // open database handle type
#define HT_DBFIND 10 // database find handle type
#define HT_SOCKET 11 // WinSock open socket handle type
#define HT_CRITSEC 12 // Critical section
#define HT_SEMAPHORE 13 // Semaphore handle type
#define HT_FSMAP 14 // mapped files
#define HT_WNETENUM 15 // Net Resource Enumeration
#define HT_AFSVOLUME 16 // file system volume handle type
#define HT_NAMESPACE 17 // namespace type
#define HT_POLICY 18 // policy type
#define HT_SECLOADER 19 // secure loader type
#define SH_LAST_NOTIFY SH_FIRST_OS_API_SET // Last set notified on Thread/Process Termination
#define SH_GDI (SH_LAST_NOTIFY+0)
#define SH_WMGR (SH_LAST_NOTIFY+1)
#define SH_WNET (SH_LAST_NOTIFY+2) // WNet APIs for network redirector
#define SH_COMM (SH_LAST_NOTIFY+3) // Communications not "COM"
#define SH_FILESYS_APIS (SH_LAST_NOTIFY+4) // File system APIS
#define SH_SHELL (SH_LAST_NOTIFY+5)
#define SH_DEVMGR_APIS (SH_LAST_NOTIFY+6) // File system device manager
#define SH_TAPI (SH_LAST_NOTIFY+7)
#define SH_CPROG (SH_LAST_NOTIFY+8) // Cprog APIS
#define SH_SERVICES (SH_LAST_NOTIFY+10)
#define SH_DDRAW (SH_LAST_NOTIFY+11)
#define SH_GWEUSER (SH_LAST_NOTIFY+13)
#define SH_CONNMGR_LEGACY (SH_LAST_NOTIFY+14) // ConnMgr legacy API
#define SH_DMSRV (SH_LAST_NOTIFY+15) // Device Management APIs
#define SH_INPUT (SH_LAST_NOTIFY+16) // Input API
#define SH_COMPOSITOR (SH_LAST_NOTIFY+17) // Window Composition
#define SH_NETCF (SH_LAST_NOTIFY+18) // .NET Compact Framework sever
#define SH_LASTRESERVED (SH_FIRST_EXT_API_SET-1)
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机制初探)
struct
_APISET {
CINFO cinfo;
/* description of the API set */
int
iReg;
/* registered API set index (-1 if not registered) */
};
其中CINFO的结构在\PRIVATE\WINCEOS\COREOS\NK\INC\apicall.h和\PRIVATE\WINCEOS\COREOS\NK\INC\kerncmn.h中定义:
struct
_CINFO {
char
acName[4];
/* 00: object type ID string */
uchar disp;
/* 04: type of dispatch */
uchar type;
/* 05: api handle type */
ushort cMethods;
/* 06: # of methods in dispatch table */
const
PFNVOID *ppfnExtMethods;
/* 08: ptr to array of methods (for external interface) */
const
PFNVOID *ppfnIntMethods;
/* 0C: ptr to array of methods (for internal interface) */
const
ULONGLONG
*pu64Sig;
/* 10: ptr to array of method signatures */
DWORD
dwServerId;
/* 14: server process id */
PHDATA phdApiSet;
/* 18: HDATA of API set */
PFNAPIERRHANDLER pfnErrorHandler;
/* 1C: ptr to the API set error handler (could be NULL) */
const
DWORD
*lprgAccessMask;
/* 20: ptr to the access mask associated with every API in this API set; valid only for handle based API sets */
};
“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进行包裹的?
疑问还非常多,这些问题以后慢慢挖掘吧,今天头已经大了。
- Windows Embedded CE 6.0 Internals (4) The Mechanism of API
- Windows Embedded CE 6.0 Internals (5) The Mechanism of API
- Windows Embedded CE 6.0 Internals (1)
- Windows Embedded CE 6.0 Internals (2)
- Windows Embedded CE 6.0 Internals (2) Memory
- Windows Embedded CE 6.0 Internals (1) Kernel Overview
- Windows Embedded CE 6.0 Internals (3) Memory Continued
- Windows Embedded CE 6.0下载地址(4)
- 安装 Windows Embedded CE 6.0
- 【原创】Windows® Embedded CE 6.0 Fundamentals 读书笔记_Chapter 4
- Renesas SH-4 Calling Sequence Specification (Windows Embedded CE 6.0)
- Modifications: Windows CE 5.0 vs. Windows Embedded CE 6.0
- 2.1.1.1:Windows Embedded CE 6.0文档
- Windows Embedded CE 6.0开发初体验
- Windows Embedded CE 6.0中某些术语
- Windows Embedded CE 6.0操作系统的架构
- Professional Microsoft Windows Embedded CE 6.0
- Windows Embedded CE 6.0 R3 发布
- Android 中H.264/AVC codec的开发
- 原生php 实现路由功能
- 英文版XP 不显示中文的情况
- 不用输入帐号密码登录MySQL的方法
- UITableView选中cell
- Windows Embedded CE 6.0 Internals (4) The Mechanism of API
- 排序算法汇总总结
- Android 中this、 getApplicationContext()、getApplication()之间的区别
- 中国软件测试现状调查报告发布啦!!
- HDU 2255 奔小康赚大钱 KM算法题解
- CONVERT(varchar(12),getdate(),112 )
- mysql一些问题的解决方法 ERROR 1045 (28000)|在同一服务器上启动不同端口
- 使用WHM重新编译Apache+PHP环境
- 专访雷果国:从1.5K到18K 一个程序员的5年成长之路