Harmony icon indicating copy to clipboard operation
Harmony copied to clipboard

Is it possible to patch native libraries?

Open mnns opened this issue 3 years ago • 5 comments

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

mnns avatar Mar 12 '22 12:03 mnns

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.

pardeike avatar Mar 12 '22 18:03 pardeike

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?

mnns avatar Mar 12 '22 18:03 mnns

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 avatar Mar 12 '22 19:03 pardeike

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 avatar Apr 23 '22 20:04 pardeike

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 avatar May 13 '22 22:05 pardeike

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.

pardeike avatar Apr 04 '23 21:04 pardeike

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)

krisrok avatar Aug 31 '23 12:08 krisrok