dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.37k stars 4.75k forks source link

Marshal.GetHINSTANCE(module) works on Windows but not on Linux/OSX #59020

Closed ndepend closed 3 years ago

ndepend commented 3 years ago

Marshal.GetHINSTANCE(module) works on Windows (net5.0 and net6.0-preview7) but not on Linux/OSX.

This program demonstrates it, its output are:

Fail on Linux
ptr:-1   .NET 6.0.0-preview.7.21377.19   OS:Linux 4.4.0-19041-Microsoft #1151-Microsoft Thu Jul 22 21:05:00 PST 2021
ptr:-1   .NET 5.0.9   OS:Linux 4.4.0-19041-Microsoft #1151-Microsoft Thu Jul 22 21:05:00 PST 2021

Work on Windows
ptr:1682875219968   .NET 6.0.0-preview.7.21377.19   OS:Microsoft Windows 10.0.19042
ptr:2688993132544   .NET 5.0.6   OS:Microsoft Windows 10.0.19042

The program:

using System.Reflection;
using System;
using System.Runtime.InteropServices;
class Program {
   static void Main(string[] args) {
      Module module = Assembly.GetExecutingAssembly().ManifestModule;
      IntPtr ptr = Marshal.GetHINSTANCE(module);
      string str = $"ptr:{ptr}   {RuntimeInformation.FrameworkDescription}   OS:{RuntimeInformation.OSDescription}";
      Console.WriteLine(str);
   }
}
AaronRobinsonMSFT commented 3 years ago

@psmacchia This is actually by-design. The HINSTANCE represents the .NET assembly loaded in memory as an OS level image (that is, PE image). This is not how the runtime loads assemblies on Linux/macOS. There is discussion about this concept at https://github.com/dotnet/runtime/issues/56331#issuecomment-897264673.

Can you elaborate on the scenario on non-Windows that is using this API?

ndepend commented 3 years ago

Thanks Aaron. The scenario is custom in-memory anti-tampering. The fact that it can be done in-memory is quite important because a file access to read the bytes is easy to detect and easy to hack.

AaronRobinsonMSFT commented 3 years ago

@psmacchia Thanks for the added details. I've done some investigation here and this isn't something we are going to enable. The reasons are related to consistency across platforms and the specific meaning of this API. Specifically the HINSTANCE on Windows is for the loaded PE image by the OS, which means it has been mapped into memory by the OS loader in a well-defined way. On non-Windows, .NET assemblies are not mapped in by the OS but instead by the runtime and they can be loaded similarly to what the Windows loader does for PE images or simply as a flat binary file. Additionally, Mono and CoreCLR differ in this behavior. The gist here is supporting this API to be consistent would have far reaching implementation ramification for a runtime and so isn't one we are going to add support for on non-Windows.

Perhaps a new API can be provided given enough justification but this specific one is not one we want to support on non-Windows platforms.

ndepend commented 3 years ago

Thanks @AaronRobinsonMSFT

Perhaps a new API can be provided given enough justification

In-memory anti-tampering could be the justification