大家好,我叫向帆,是C++上海团队的开发者。
今天我想谈谈与安全性相关的两个链接器选项:/DYNAMICBASE和/NXCOMPAT。
这两个选项是在VS2005中引入的,旨在提高本机应用程序的整体安全性。
您可以在VS IDE中显式设置这两个选项:
这两个选项在IDE中有三个可用值:On、Off和Default。
如果使用VS2008向导创建本机C++应用程序,它们将被设置为“on”。
当VS2008升级不支持这些选项的旧版本VC创建的项目时,升级后会将它们设置为“关闭”。
如果您将它们设置为“Default”,链接器会将其视为“Off”。
经过几年的采用,我们计划将VS2010中的“Default”行为改为“On”,以增强安全性。我们想得到你的反馈。
以下是有关这两个选项的详细信息:
1. 动态数据库
/DYNAMICBASE修改可执行文件的头,以指示操作系统是否应在加载时对应用程序进行随机重定基。随机重基被称为ASLR(地址空间布局随机化)。
此选项还意味着“/FIXED:NO”,它将在可执行文件中生成重定位部分。看到了吗 /固定 更多信息。
在VS2008中,如果组件需要Windows Vista,则默认情况下此选项处于启用状态( /子系统 6.0及更高版本)
/DYNAMICBASE:NO可用于显式禁用随机重基。
本文讨论ASLR: http://technet.microsoft.com/en-us/magazine/cc162458.aspx
ASLR仅在Windows Vista和更高版本的操作系统上受支持。在旧操作系统上它将被忽略。
ASLR对应用程序是透明的。使用ASLR,唯一的区别是OS将无条件地重新设置可执行文件的基础,而不是仅在存在基于映像的冲突时才这样做。
2. NXCOMPAT公司
/NXCOMPAT用于指定与DEP兼容的可执行文件 (数据执行预防)
请注意,此选项仅适用于x86可执行文件。如果可执行文件未在WOW64模式下运行,则桌面窗口的非x86体系结构版本(例如x64和IA64)始终强制执行DEP。
以下是对DEP的全面描述:
http://support.microsoft.com/kb/875352
如果组件需要Windows Vista,则默认情况下此选项处于启用状态( /子系统 6.0及更高版本)。
/NXCOMPAT:NO可用于显式指定可执行文件与DEP不兼容。
但是,即使可执行文件没有指定为与DEP兼容,管理员仍然可以启用DEP。因此,您应该始终在DEP打开的情况下测试应用程序。
Windows Vista SP1、Windows XP SP3和Windows Server 2008添加了新的API 设置进程策略 允许开发人员在运行时在其进程上设置DEP,而不是使用链接器选项。有关详细信息,请参见以下链接:
有几种常见的(和不完整的)模式与DEP不兼容(请参阅 http://msdn.microsoft.com/en-us/library/aa366553.aspx 更多信息。)
答。 在堆或堆栈中生成的动态代码
如果应用程序必须从内存页运行代码,则必须分配和设置适当的虚拟内存页 记忆保护 属性。
分配内存时,必须将分配的内存标记为PAGE U EXECUTE、PAGE U EXECUTE U READ、PAGE U EXECUTE U READWRITE或PAGE U EXECUTE U WRITECOPY。通过调用 新的 , 马洛克 和 中分配内存 函数是不可执行的。应用程序可以使用 虚拟的 函数来分配具有适当内存保护选项的可执行内存。
另一个选项是在通过创建堆时传递HEAPu CREATEu ENABLEu EXECUTE 堆创建。随后HeapAlloc分配的内存将是可执行的。
b。 数据段中的可执行代码
它们应该迁移到一个代码段
安全漏洞比启用DEP时更容易被利用。因此,您应该始终使应用程序与DEP兼容并打开DEP。
以下示例 演示与DEP不兼容的代码。
它还展示了在堆上运行代码的两种与DEP兼容的方法。
在数据段或堆栈中运行代码几乎总是意味着安全漏洞。您必须将代码放在代码段或堆中。
#包括 “windows.h”
#包括
类型定义 无效 (*funType)();
未签名 烧焦 gCode[]={0xC3}; //x86上的“ret”指令
常数 大小代码= 大小 (G代码);
//这些与DEP不兼容
无效 RunCodeOnHeap()
{
未签名 烧焦 *代码= 新的 未签名 烧焦 [gCodeSize];
memcpy(代码,gCode,gCodeSize);
趣味= 重新解释
乐趣();
删除 []代码;
}
//这些是DEP兼容的
无效 RunCodeOnHeapCompatible1()
{
未签名 烧焦 *代码=( 未签名 烧焦 *)·VirtualAlloc(NULL,gCodeSize,MEMu COMMIT,PAGEu READWRITE);
memcpy(代码,gCode,gCodeSize);
DWORD flOldProtect公司;
·VirtualProtect(代码、gCodeSize、PAGEu EXECUTEu READ和flOldProtect);
趣味= 重新解释
乐趣();
·VirtualFree(代码,0,内存释放);
}
无效 RunCodeOnHeapCompatible2()
{
HANDLE hheap=::HeapCreate(HEAPu CREATEu ENABLEu EXECUTE,0,0);
未签名 烧焦 *代码=( 未签名 烧焦 *)·HeapAlloc(hheap,0,gCodeSize);
memcpy(代码,gCode,gCodeSize);
趣味= 重新解释
乐趣();
:堆自由(hheap,0,代码);
·HeapDestroy(hheap);
}
INT depenceptionfilter(LPEXCEPTIONu指针lpInfo)
{
//请检查 http://technet.microsoft.com/en-us/library/bb457155.aspx
//了解更多信息
如果 (lpInfo->ExceptionRecord->ExceptionCode==状态u访问u冲突)&&
lpInfo->异常记录->异常信息[0]==8){
返回 异常执行处理程序;
}
返回 异常u继续u搜索;
}
内景 主()
{
__试试看
{
RunCodeOnHeap();
打印F( “RunCodeOnHeap:好的” );
}
__除外 (DEPExceptionFilter(GetExceptionInformation()))
{
打印F( “RunCodeOnHeap:由于DEP而失败” );
}
__试试看
{
RunCodeOnHeapCompatible1();
打印F( “RunCodeOnHeapCompatible1:好” );
}
__除外 (DEPExceptionFilter(GetExceptionInformation()))
{
打印F( “RunCodeOnHeapCompatible1:由于DEP而失败” );
}
__试试看
{
RunCodeOnHeapCompatible2();
打印F( “RunCodeOnHeapCompatible2:确定” );
}
__除外 (DEPExceptionFilter(GetExceptionInformation()))
{
打印F( “RunCodeOnHeapCompatible2:由于DEP而失败” );
}
}
输出:
cl测试.cpp/链接/nxcompat:no
RunCodeOnHeap:好的
RunCodeOnHeapCompatible1:确定
RunCodeOnHeapCompatible2:确定
cl测试.cpp/link/nxcompat
RunCodeOnHeap:由于DEP而失败
RunCodeOnHeapCompatible1:确定
RunCodeOnHeapCompatible2:确定
总之,“cl test.cpp”相当于“cl test.cpp/link”/nxcompat:no /dynamicbaseVS2010之前:否。我们计划在VS2010中将其更改为“cl test.cpp/link/nxcompat/dynamicbase”。
如果您对这两个选项的默认行为改变有任何顾虑,请毫不犹豫地给出您的反馈。谢谢!
当做,
向