pardeike / Harmony

A library for patching, replacing and decorating .NET and Mono methods during runtime
https://www.patreon.com/pardeike
MIT License
5.28k stars 492 forks source link

Is it possible to patch native libraries? #459

Closed mnns closed 10 months ago

mnns commented 2 years ago

I'd like to patch MessageBox (a win32 dll)

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType);

I'm not sure if I can patch DllImport for example or otherwise.

Thanks

pardeike commented 2 years ago

Right now, native patches are restricted to full replacements. Once a method is patched, the original is destroyed by writing a jump instruction to the replacement. That makes patching native methods destructive and you can only write a transpiler that outputs the IL of your own code. Since the original is broken you cannot call the original from within your code and Harmony cannot either - thus Prefix/Postfix won't work.

mnns commented 2 years ago

Right now, native patches are restricted to full replacements. Once a method is patched, the original is destroyed by writing a jump instruction to the replacement. That makes patching native methods destructive and you can only write a transpiler that outputs the IL of your own code. Since the original is broken you cannot call the original from within your code and Harmony cannot either - thus Prefix/Postfix won't work.

Thanks, is there a plan to fix this?

pardeike commented 2 years ago

This is very deep in the design of Harmony. If I would know how to do it I would implement it. At least one other solution does a very dirty switch on the bytes the jump is written but to me this looks very dangerous because it would not work in multithreaded scenarios.

pardeike commented 2 years ago

There seems to be a clever way to make this work. It requires some trickery so it's not trivial to implement. I will get to you when I have plenty of time to make it work correctly.

pardeike commented 2 years ago

More feedback from the MonoMod discord by DaNike seems to indicate that native methods share entrance points and it is therefore not safe to patch multiple native methods.

So for now this is a WONTFIX

pardeike commented 1 year ago

In https://github.com/pardeike/Harmony/tree/feature/monomod-core I am moving over to MonoMod.Core which means that we will get the chance to patch native methods in the future. I will remove the WONTFIX.

krisrok commented 1 year ago

Oh well... at least from my limited testing it turns out it just works with the current version (https://github.com/pardeike/Harmony/commit/5c42611d90cb23fa6ddd2a78e086ccb838452d2c). 🤦‍♂️ Possibly since the switch to MonoMod?

Prefixing MessageBox like in @mnns's opening post works.

Postfixing Unity3D's UnityEngine.GameObject.SetActive() works too. And it is defined as

[MethodImpl(MethodImplOptions.InternalCall)]
[NativeMethod(Name = "SetSelfActive")]
public extern void SetActive(bool value);

(Editor-only, I did not test this any further with a built project let alone IL2CPP)