Mono x86-32 JIT machine code hooks

Started by RawCode, December 24, 2015, 05:38:45 AM

Previous topic - Next topic

RawCode

This code shows how to modify code of methods, there are no limits on actions you can perform.

This could allow to inject custom vtable, but it is not designed for this and wont do it without specific modifications.


Fluffy (l2032)

@Isistoy, yep, pretty much.

Also, the version here doesn't work on mac os x. E made some adaptations to allow a 64 bit method ( os x only runs 64bit code ), and some small tweaks. It's included in CCL 0.12.7, but you can find the updated code here;

https://github.com/RimWorldCCLTeam/CommunityCoreLibrary/blob/master/DLL_Project/StaticClasses/Detours.cs

Wivex

How can i detour the override\virtual method?

isistoy

+1
Will we ever get access to the context of the object containing the method that is detoured?
Not really hopeful here...

Also, can it be made so that the method to detour is called with ours? (+= new delegate() sthg?)
<Stay on the scene like a State machine>

Fluffy (l2032)

Not really in the current way of doing things. The problem is the first few bytes of the 'old' method are overwritten with a jump to the new method, pretty much destroying what was there.

In theory I'm sure it's possible to copy the old method to a new one, see for example here;
http://stackoverflow.com/questions/24350769/copy-method-from-another-appdomains-assembly-and-execute-it-from-currentdomain
But thats going squarely into the domain of self-altering code, which is horrible to debug in the best of circumstances, and virtually impossible with the limited options we have in RimWorld.

So I'm afraid it's still the good old copy/paste from core. The good news is that you only have to copy paste the one method - not everything that calls it as well.

That said, a truly dynamic way to basically turn any method whatsoever into an event that can be hooked into would be awesome, so if anyone feels like spending a couple of months figuring this out, please know I'd send you cookies.

TheGentlmen

Quote from: Fluffy (l2032) on February 21, 2016, 10:47:48 AM
That said, a truly dynamic way to basically turn any method whatsoever into an event that can be hooked into would be awesome, so if anyone feels like spending a couple of months figuring this out, please know I'd send you cookies.
I did this months ago and suggested it into CCL. I got totally shot down.

I called the C# compiler and had it compile an function overrider (the same one I got you guys a while ago) that detoured to an event with the correct signature, then made a wrapper for it so you can pass delegates and get (un)subscribed to the event.

Currently thier is no undo function, but a possibility is to save the first few bites in the function and replace them with what they used to be when your done.

As for copy pasting functions, also possible but don't expect me to do it, I've moved on to new projects.

LINK:
https://github.com/TheGentzy/FunctionJumping

Fluffy (l2032)

IIRC your approach required making a copy of the detouring class for every method/class in the vanilla code, which isn't exactly what I'd call truly dynamic.

TheGentlmen

Quote from: Fluffy (l2032) on February 21, 2016, 12:30:15 PM
IIRC your approach required making a copy of the detouring class for every method/class in the vanilla code, which isn't exactly what I'd call truly dynamic.

Which is why I compile one! Every time you call the function I compile one just for you!

Fluffy (l2032)

well, if that actually works, and you've still got it lying around, I'd love to give it a try.

TheGentlmen

#39
I gave ya the link! Lazy people!  ;D

Anyway here is the C# code:
https://github.com/TheGentzy/FunctionJumping/blob/master/Function%20Jumping/Program.cs

main() shows how to use it, its pretty crude I must say.

EDIT:
The actual functions are here:
https://github.com/TheGentzy/FunctionJumping/blob/master/FunctionJumper/ReturnCodes.cs
https://github.com/TheGentzy/FunctionJumping/blob/master/FunctionJumper/EventMaster.cs
https://github.com/TheGentzy/FunctionJumping/blob/master/FunctionJumper/EventInterface.cs

EDIT2:
For the lazy who can't bother to use compilers:
Results from overriding 4 different functions (NOTE: 0's are not the function outputs)

A API
B API
C OVERRIDE
81
D API
-29
HIT ENTER!!!



0
0
0
0

0
0
0
0

A NORM
B NORM
C NORM
9
D NORM
-44
HIT ENTER!!!

0
0
0
0

A NORM
A NORM
B NORM
B NORM
C NORM
C NORM
9
D NORM
D NORM
-44
HIT ENTER!!!

0
0
0
0

A NORM
B NORM
C NORM
9
D NORM
-44
HIT ENTER!!!

Fluffy (l2032)

make it work without requiring users to install a C# assembler, and for instance methods, then write a simple proof of concept mod that implements it, and I will send you those cookies.

TheGentlmen

Quote from: Fluffy (l2032) on February 21, 2016, 05:47:05 PM
make it work without requiring users to install a C# assembler,

Mabey the C# assembler comes with the runtimes! Have you checked?

Quote from: Fluffy (l2032) on February 21, 2016, 05:47:05 PM
and for instance methods,

Can't be bothered. That requires passing instances and stuff.

Quote from: Fluffy (l2032) on February 21, 2016, 05:47:05 PM
then write a simple proof of concept mod that implements it
working on it.

isistoy

#42
Quote from: Fluffy (l2032) on February 21, 2016, 10:47:48 AM
Not really in the current way of doing things. The problem is the first few bytes of the 'old' method are overwritten with a jump to the new method, pretty much destroying what was there.
Virtual base calls and object context (class instance members) are show stoppers for me, right now..
Doesn't mean it's not useful, but it seems obviously limited to some uses.

Quote from: Fluffy (l2032) on February 21, 2016, 10:47:48 AM
In theory I'm sure it's possible to copy the old method to a new one, see for example here;
http://stackoverflow.com/questions/24350769/copy-method-from-another-appdomains-assembly-and-execute-it-from-currentdomain
But thats going squarely into the domain of self-altering code, which is horrible to debug in the best of circumstances, and virtually impossible with the limited options we have in RimWorld.
Agreed. Plus, honestly, I am in no way close to being able to decypher use of unsafe blocks using pointers manip. and asm instructions. Meaning my brain can't deal with any weird pb that could happen combining it with .net marshaling or basically anything else :D

Quote from: Fluffy (l2032) on February 21, 2016, 10:47:48 AM
So I'm afraid it's still the good old copy/paste from core. The good news is that you only have to copy paste the one method - not everything that calls it as well.
As always, if your use for sthg like this doesn't fit, reconsider why you would use it in the first place. I should do that more often ;)

Quote from: Fluffy (l2032) on February 21, 2016, 10:47:48 AM
That said, a truly dynamic way to basically turn any method whatsoever into an event that can be hooked into would be awesome, so if anyone feels like spending a couple of months figuring this out, please know I'd send you cookies.
If that means propagate all class instance members (through a context object of some sort) and have pre/post triggers to plug in to (jump), I'd say how high!
<Stay on the scene like a State machine>

RawCode

there is no stoppers since mono source code available and you always can go native if something really bad happens.

proper way of doing "hooks" is patching call instructions only, without doing damage to methods.

if method A calls method B, instead of damaging method B with jump opcode, we should patch method A.

this also will allow to call method B from methods C and D without any interference.

i will provide some time later methods to resolve jit stubs into actual methods and methods to parse raw assembly into instructions for easy and safe processing, basically, this is only things that required to implement efficient and safe hooks.

isistoy

#44
Quote from: RawCode on February 22, 2016, 04:16:35 AM
there is no stoppers since mono source code available and you always can go native if something really bad happens.
They are for me, with my current set of abilities. I should have made that clear, sry.
Can't wrap my head around the idea jumping into the context of another class instance method and potentially missing access to that particular instance private object members or class hierarchy.

EDIT: now, we are talking! Context is there, apparently unchanged and perfectly responding.
Stack call to base.Method() and other members defined/cloned from original class look available.
Had to also dummy implement some abstracts to pass compilation, but so far so good!

Quote
proper way of doing "hooks" is patching call instructions only, without doing damage to methods.

if method A calls method B, instead of damaging method B with jump opcode, we should patch method A.

this also will allow to call method B from methods C and D without any interference.

i will provide some time later methods to resolve jit stubs into actual methods and methods to parse raw assembly into instructions for easy and safe processing, basically, this is only things that required to implement efficient and safe hooks.
Being able to hook a particular call with a block of your own looks promising. :)
Do you mean replacing the initial or also, maybe just complementing it?
<Stay on the scene like a State machine>