强制使用x86 CLR在“Any CPU” .NET程序集上。

57
在.NET中,“平台目标:任何CPU”编译选项允许.NET程序集在x64机器上以64位方式运行,在x86机器上以32位方式运行。同时,也可以使用“平台目标:x86”编译选项强制程序集在x64机器上以x86方式运行。
是否可以使用“任何CPU”标志运行程序集,但是确定它是否应在x86或x64 CLR上运行?通常,根据底层系统的位数,此决策由CLR / OS加载程序(据我所知)做出。
我正在尝试编写一个C# .NET应用程序,该应用程序可以与(读取:注入代码)其他正在运行的进程进行交互。 x64进程只能注入到其他x64进程中,而对于x86同理。理想情况下,我希望利用JIT编译和“任何CPU”选项,使单个应用程序可以用于注入到x64或x86进程(在x64机器上)中。
这个想法是将应用程序编译为“任何CPU”,在x64机器上运行为x64。如果目标进程是x86,则应该重新启动自己,强制CLR将其作为x86运行。这可行吗?
4个回答

60

您可以使用CorFlags应用程序静态地查看应用程序的运行方式并进行更改。要了解应用程序的运行方式,请使用:

corflags <PathToExe>

要更改应用程序的运行方式,请使用:

corflags /32bit+  <PathToExe>

这将使EXE文件作为32位进程运行。关于程序集如何运行的信息存储在PE头中。请参见Stack Overflow问题如何查找本机DLL文件是否编译为x64或x86?
如果您想在运行时注入代码,则必须使用C++ / COM编写.NET分析器。有关更多详细信息,请参见.NET Internals: The Profiling APIProfiling (Unmanaged API Reference)
您需要实现JitCompilationStarted回调并在那里完成您的工作。如果您选择这个方向,您将需要在x86和x64上都构建注入的DLL文件。本机DLL文件将在以下环境变量设置后由CLR加载:
Cor_Enable_Profiling=0x1
COR_PROFILER={CLSID-of-your-native-DLL-file}

如果设置正确,64位版本将“看到”64位进程,32位版本将“看到”32位进程。

谢谢提供信息 :) 我知道 corflags 应用程序,但我想知道是否有任何方法在运行时以编程方式实现类似的结果。 - jeffora
1
一旦进程运行,就没有办法改变它的上下文! - Ohad Horesh
在运行时更改上下文并不仅意味着在PE头部设置一个位,32位进程正在WOW仿真层下运行。我无法想象进程如何保存其运行状态,进行上下文切换并继续运行。请参考此链接:http://blogs.msdn.com/oldnewthing/archive/2008/12/22/9244582.aspx - Ohad Horesh
10
我不是要求在运行时改变进程上下文,而是说我有一个编译为AnyCPU的汇编文件a.exe,在x64机器上以64位运行。如果它需要注入32位,我希望它启动一个新的实例(Process.Start("a.exe"))并强制该新实例以x86模式启动。 - jeffora

9

我相信,调用程序的位数决定了汇编代码是否会被编译为x86或x64。虽然我已经有一段时间没有尝试过这个方法。

所以,如果您编写一个小型控制台应用程序并将其构建为x86,另一个构建为x64,则运行其中之一将导致加载到进程中的其他程序集以32位或64位运行。当然,这是在64位机器上运行的情况下。


4
我知道你可以通过将代码放入x86启动程序集中来强制执行,但我想知道是否可以动态地为“任何CPU”编译的程序集强制执行。无论如何,还是谢谢你,如果找不到其他方法,我可能会回到这种方法。我想点赞但声望值不够。 - jeffora
1
进程可以是64位或32位。如果程序集在32位进程中加载,并且它被构建为任何CPU,它将被JIT编译为32位,在64位进程中将被JIT编译为64位。您打算如何创建托管程序集的程序集? - jnoss

6
我曾经通过创建两个(实际上是三个)二进制文件来做类似的事情。我有一个检测我要注入的进程是32位还是64位的程序。该程序将启动您注入二进制文件的32位或64位版本(而不是像您提到的那样重新启动自己)。
听起来很混乱,但您可以在构建时轻松实现此目标,使用后期构建事件复制您的输出二进制文件并使用CorFlags实用程序强制将副本作为32位运行。这样,您就不必将CorFlags实用程序与应用程序一起部署,这可能出于某种原因是非法的。
我认为这与您最初的想法非常相似,除了需要一个两行的构建事件外,不需要更多的工作。

6

我不确定我能否帮助你解决这个问题,但这是我的经验。

我有一个主机应用程序A.exe(编译为x86),还有一个客户端应用程序B.exe(编译为ANY CPU),从主机应用程序中启动B.exe,使用System.Diagnostic.Process类。

现在的问题是,如果我将它们放在一个x64的机器上,那么A.exe将作为x86运行,而B.exe将作为x64运行

但是,如果A.exe调用了程序集c(c.dll,编译为Any CPU),并且B.exe也调用了c.dll,那么c.dll将遵循调用它的应用程序。换句话说,在64位机器上,当A.exe调用它时,它将像x86 dll一样运行,而当B.exe调用它时,它将像x64运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接