2008年7月30日星期三

挖掘WinCE 5系统调用过程

int shellcode[] =
{
0xE59F0014, // ldr r0, [pc, #20]
0xE59F4014, // ldr r4, [pc, #20]
0xE3A01000, // mov r1, #0
0xE3A02000, // mov r2, #0
0xE3A03000, // mov r3, #0
0xE1A0E00F, // mov lr, pc
0xE1A0F004, // mov pc, r4
0x0101003C, // IOCTL_HAL_REBOOT
0xF000FE74, // trap address of KernelIoControl
};
这是黑客常用的缓冲攻击代码形式,这里的32为常数,都是ARM机器指令。
我就要想你展示的不是如何攻击WinCE内核,而是看看WinCE的系统调用是如何实现的。WinCE一个常用的API,KernelIoControl,它的实现体实在内核NK.exe,而function caller只是一个trusted的user级别的application。
你可以想象,这样的API的实现,必然要经历CPU从user processer mode切换到supervisor processer mode。
BOOL KernelIoControl(
DWORD dwIoControlCode,
LPVOID lpInBuf,
DWORD nInBufSize,
LPVOID lpOutBuf,
DWORD nOutBufSize,
LPDWORD lpBytesReturned
);
KernelIoControl超过了4个参数,那么在参数传递时,超过的部分使用堆栈完成的。IOCTL_HAL_REBOOT的参数都没什么用,所以这个我们忽略,传0就可以了,因此r1,r2,r3赋值0.
IOCTL_HAL_REBOOT的数值必须放在寄存器r0。
上面的代码中r4的内容会变为0xF000FE74,代码最后就是跳转到0xF000FE74,你可以看到这个地址很大,在整个内存空间的高地址。同时这个地址是经过编码得到,公式是:
0xf0010000-(256*apiset+apinr)*4
对于KernelIoControl,apiset是0,apinr是99。0xF000FE74是这样得到的。
当代码跳转的这样一个高地址时,会引发prefetch abort,这样exception会被内核 ,也就是NK.exe抓到。然后再对这个出错地址进行解析,就可以知道应用程序想访问那个system cal。
综上,WinCE并不是靠SWI这样的软中断实现system call,而是prefetch abort。

1 条评论:

匿名 说...

I really like when people are expressing their opinion and thought. So I like the way you are writing