如何解决R6034错误,实现在WIN7以上版本通过LoadLibrary加载msvcr90.dll等DLL
2016-01-14 15:30
435 查看
在XP以前,安装VC运行时库时,安装包只会将各种DLL释放到system32目录并注册相关信息到注册表,这样LoadLibrary时加载这些DLL也不会出错,因为对于应用程序来说,当前只有一个对应的运行时库被注册到系统中,不存在多个不同版本的问题,但也很容易造成兼容性问题,如使用VS2008编译的程序,在仅安装了VS2005运行时库的系统中可能会出现崩溃错误。
到了WIN7,WIN8,WIN10 后,为了在系统中同时提供多种CPU平台和不同VS版本的运行时库来兼容不同的应用软件,微软做了大概下面3个改进,
1)在VS开发时,可在工具中设置manifest来指定当前程序使用的运行时库版本(如win32 x86 版本号 等等),manifest可以嵌入到资源中,也可以放在本地的xml格式的文本文件
2)在C:\Windows\WinSxS中存放各种不同版本的运行时库
有了上面的2个改进,剩下的无非就是系统运行EXE文件或者加载DLL时,如何通过manifest的配置项来正确加载相应的运行时库了。
目前最标准的也是VS开发工具的做法,就是将运行时库通过导入表静态链接到PE文件(EXE或DLL),同时将manifest嵌入到PE文件的资源里,资源号是RT_MANIFEST(24), 再交给系统的PE加载器去自动加载对应的运行时库,虽然本文是说MSVCR90.DLL,但原理上是可以适用于各种各样的运行时库的。
系统在创建进程时,在NTDLL和内核中有部分API和代码统称为PE加载器,在EXE使用LoadLibrary加载DLL时,内部也是一个类似的且专门映射DLL到进程的PE加载器,所以这里说加载器仅仅是一个模块概念,并不是一个实际的EXE程序。
如果采用Loadlibrary去动态加载MSVCR90.DLL,在XP上大部分是正常的,在VISTA/WIN7以上可能就会报错R6034,这是因为调用LoadLibrary的EXE程序没有嵌入包含运行时库依赖信息的manifest,所以加载器无法通过当前进程的manifest找到正确的MSVCR90.DLL,最终报错。
要解决该问题,就需要让加载器能够获取到正确的manifest信息,而manifest信息其实只是一个载体,实际上的使用对象是叫做ActiveContext,也就是说manifest最终会被ActiveContext加载并接管处理。而加载器也是通过ActiveContext来处理被解析映射过的manifest信息。
总体上,就是只要进程中存在正确的ActiveContext,加载器就能够取得正确的依赖库路径并加载。
文章到这里已经相对清晰了,要解决本文提到的问题,现在变成了如何创建包含manifest的ActiveContext,到这里还没有解释ActiveContext是什么,有兴趣的朋友可以查找MSDN中关于“Activation Context”的信息。
下面给出代码展示如何使用LoadLibrary加载msvcr90.dll,先看一段正常但会报错的代码:
上面这段代码在WIN7或WIN10上一执行,通常情况下就会弹出R6034的错误,而以下代码则可避免该问题
以上代码所使用的manifest内容随便找一下就有,具体如下(从某个VC程序的资源中拷贝出来的):
注意其中的版本号,如果系统中没有安装对应的运行时库,仍然会有可能报错。
本文提到的方法同样适用于shellcode对PE文件加壳时需要面对的manifest处理问题。
注:
A . 关于WinSxs(即Windows Side-by-Side),更高级的操作可查找Sxs.dll相关API,号称完美解决不同版本COM和DLL兼容性问题(最初应该是解决.NET不同framework版本的兼容性问题)
B. manifest是一个范围较大的配置文件,可在以后为某些新的功能增加更多配置项,而运行时库依赖配置仅仅是其中一项
到了WIN7,WIN8,WIN10 后,为了在系统中同时提供多种CPU平台和不同VS版本的运行时库来兼容不同的应用软件,微软做了大概下面3个改进,
1)在VS开发时,可在工具中设置manifest来指定当前程序使用的运行时库版本(如win32 x86 版本号 等等),manifest可以嵌入到资源中,也可以放在本地的xml格式的文本文件
2)在C:\Windows\WinSxS中存放各种不同版本的运行时库
有了上面的2个改进,剩下的无非就是系统运行EXE文件或者加载DLL时,如何通过manifest的配置项来正确加载相应的运行时库了。
目前最标准的也是VS开发工具的做法,就是将运行时库通过导入表静态链接到PE文件(EXE或DLL),同时将manifest嵌入到PE文件的资源里,资源号是RT_MANIFEST(24), 再交给系统的PE加载器去自动加载对应的运行时库,虽然本文是说MSVCR90.DLL,但原理上是可以适用于各种各样的运行时库的。
系统在创建进程时,在NTDLL和内核中有部分API和代码统称为PE加载器,在EXE使用LoadLibrary加载DLL时,内部也是一个类似的且专门映射DLL到进程的PE加载器,所以这里说加载器仅仅是一个模块概念,并不是一个实际的EXE程序。
如果采用Loadlibrary去动态加载MSVCR90.DLL,在XP上大部分是正常的,在VISTA/WIN7以上可能就会报错R6034,这是因为调用LoadLibrary的EXE程序没有嵌入包含运行时库依赖信息的manifest,所以加载器无法通过当前进程的manifest找到正确的MSVCR90.DLL,最终报错。
要解决该问题,就需要让加载器能够获取到正确的manifest信息,而manifest信息其实只是一个载体,实际上的使用对象是叫做ActiveContext,也就是说manifest最终会被ActiveContext加载并接管处理。而加载器也是通过ActiveContext来处理被解析映射过的manifest信息。
总体上,就是只要进程中存在正确的ActiveContext,加载器就能够取得正确的依赖库路径并加载。
文章到这里已经相对清晰了,要解决本文提到的问题,现在变成了如何创建包含manifest的ActiveContext,到这里还没有解释ActiveContext是什么,有兴趣的朋友可以查找MSDN中关于“Activation Context”的信息。
下面给出代码展示如何使用LoadLibrary加载msvcr90.dll,先看一段正常但会报错的代码:
procedure LoadMSVCRT(); var sDllName: string; begin sDllName := 'MSVCR90.DLL'; hLib := LoadLibrary(PChar(sDllName)); end;
上面这段代码在WIN7或WIN10上一执行,通常情况下就会弹出R6034的错误,而以下代码则可避免该问题
procedure LoadMSVCRT(); var sDllName: string; hLib: HModule; aActCtx: TActCtx; hCtx: THandle; lpCookie: ULONG_PTR; begin // 激活清单文件,可正确加载MSVCR90.DLL FillChar(aActCtx, SizeOf(TActCtx), 0); aActCtx.cbSize := SizeOf(TActCtx); aActCtx.lpSource := PChar(ExtractFilePath(ParamStr(0))+'MSVCRT.manifest'); hCtx := Winapi.Windows.CreateActCtx(aActCtx); if hCtx<>INVALID_HANDLE_VALUE then begin Winapi.Windows.ActivateActCtx(hCtx, lpCookie); end; sDllName := 'MSVCR90.DLL'; hLib := LoadLibrary(PChar(sDllName)); if hCtx<>INVALID_HANDLE_VALUE then begin DeactivateActCtx(0, lpCookie); ReleaseActCtx(hCtx); end; end;
以上代码所使用的manifest内容随便找一下就有,具体如下(从某个VC程序的资源中拷贝出来的):
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel> </requestedPrivileges> </security> </trustInfo> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity> </dependentAssembly> </dependency> </assembly>
注意其中的版本号,如果系统中没有安装对应的运行时库,仍然会有可能报错。
本文提到的方法同样适用于shellcode对PE文件加壳时需要面对的manifest处理问题。
注:
A . 关于WinSxs(即Windows Side-by-Side),更高级的操作可查找Sxs.dll相关API,号称完美解决不同版本COM和DLL兼容性问题(最初应该是解决.NET不同framework版本的兼容性问题)
B. manifest是一个范围较大的配置文件,可在以后为某些新的功能增加更多配置项,而运行时库依赖配置仅仅是其中一项
相关文章推荐
- Go在linux下的安装
- linux commond
- Linux服务器配置——搭建SVN服务器
- android Notification分析——你可能遇到的各种问题
- 冒泡排序
- 使用junitreport生成报告时,发生异常的情况
- _WIN32_WINNT
- 【Java】生成验证码(图片、汉字)
- Pop3_解决PKIX:unable to find valid certification path to requested target 的问题
- 复制列表
- unity3d扩展编辑器
- jquery ajax 使用layer的超时提示
- iOS开发之:dispatch_async 与 dispatch_get_global_queue 的使用方法
- 系统上电后 bootloader的执行流程及 ARM Linux的启动过程分析
- 中医教你怎么睡好觉,睡个养生觉!
- Commons CLI使用
- WPF Issues
- js实例代码
- MySQL innodb表空间
- Android隐藏标题状态栏的方法