在2017年3月份初,有客户在报有电脑程序加载不上,其他电脑运行正常故障,一直没引起注意。最初以为是他们用家庭版,权限太低的原因,就让运维帮他们把系统换成专业版,主要是在win7升级win8或win10后,家庭版权限确实被限制了不少,特别是写注册表或者读取注册表之类的操作,所以ocx插件出现的问题就比较明显。
但在九月份去湖北出差,发现win10专业版,即使是提升到最高权限,OCX插件依然加载不上,通过几番排查,发现是操作系统更新到最新后的问题,最后排查问题出在程序中使用minidumper来记录程序崩溃时进行写文件的操作代码有问题,由于当时比较紧急,直接把相关dump代码屏蔽了,后面一直没进行处理。
直到最近发现现网又出现实时视频崩溃,跟了好久也没跟出来,不得不继续启用dump记录,由于时间稍微宽松,所以彻底排查了翻,发现引起程序起不来的原因主要是在调用了DisableSetUnhandledExceptionFilter函数时引起,再往里面跟由于
VirtualProtect(addr, size, PAGE_EXECUTE_READWRITE, &dwOldFlag);
WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
来看看msdn对VirtualProtect函数的介绍:
BOOL WINAPI VirtualProtect(
_In_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flNewProtect,
_Out_ PDWORD lpflOldProtect
);
lpAddress,要改变属性的内存起始地址。
dwSize,要改变属性的内存区域大小。
flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行。
pflOldProtect,内存原始属性类型保存地址。
修改内存属性成功时函数返回非0,修改失败时返回0。
如果我们能够按照如下参数布置好栈帧的话就可以将shellcode所在内存区域设置为可执行模式。
由此猜想可能是第三个参数是设置权限的,将上述代码改为:
VirtualProtect(addr, size, PAGE_EXECUTE_READWRITE, &dwOldFlag);
再次进行测试,发现程序已经能够正常运行。由此可以得出结论其实还是操作系统权限的问题,目前在win10家庭版:版本 10.0.16299.192,win10专业版:版本 10.0.16299.192,已经验证正常。