有时候,你可能会偷些懒
在动态生成某些可执行代码(shellcode)的时候,忘记去执行VirtualProtect(PAGE_EXECUTE)。对于i386这样的处理器来说,这样做并没有什么问题。
因为这些处理器并没有带有一个”可读但不可执行”的工作模式,所以在页面上任何可以读取的东西,都是可以被执行的。
关于这个VirtualProtect
VirtualProtect是一个Win32 API,它会变更调用进程的指定页面的保护层级。
其函数原型如下:
BOOL VirtualProtect(
LPVOID lpAddress,
DWORD dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
参数解析
lpAddress: 要改变保护层级的页面(内存)起始地址。
dwSize:页面(内存)大小。
flNewProtect:新的保护层级值。设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行。全部可供设置的保护层级,请参考MSDN。
pflOldProtect:原内存保护层级地址。
返回值
页面保护层级修改成功时函数返回非0,修改失败则返回0。
以下代码可以将ShellCode所在的内存区的保护层级设置为可执行模式。
BOOL VirtualProtect(
ShellCode所在页面的起始地址,
ShellCode代码大小,
PAGE_EXECUTE_READWRITE,
指定一个可写入的地址
);
现在不行了
从Windows XP SP2开始,在支持这一模式的处理器上(根据官方文档,当前有AMD K8,安腾和AMD64),栈和堆将不可执行任何代码。如果你尝试在栈或者堆上执行代码,则处理器会产生一个异常并阻止代码的执行。
换句话说,就是页面的执行保护特性将被强制应用在系统上。(实际上,我相信安腾版Windows XP已经启用了这项新的保护层级,所以如果曾经玩过这个系统,则应该会看到它。)
如果你是一个”好的”开发者,遵循有关页保护的所有行为准则,则这个行为变更对你没有任何的影响。但是如果你尝试欺骗或者绕开这一准则,并使用了针对特定硬件的实现细节,则你就可能会碰到些麻烦。
就权当一个预警吧。
领取专属 10元无门槛券
私享最新 技术干货